Read stock
No V3 Stock API
Stock endpoints are part of the V1/V2 API. There are no V3 stock endpoints. Use the endpoints documented below.
Contents
- Overview
- ERP Context
- Understanding the Stock Response
- Endpoints Overview
- Get Stock Totals for a Product
- Get Storage Locations for a Product
- Get Reservations for a Product
- List Warehouses
- List Storage Locations in a Warehouse
- Get Items at a Storage Location
- Common Integration Patterns
- Storage Location Types
- Polling and Rate Limits
- Error Handling
- Related Resources
Overview
This guide shows you how to read stock data from Xentral via the API. You will learn how to query stock levels, understand different stock types, find which warehouses and storage locations hold your products, and check reservations.
Use Cases:
- Sync stock levels to your online shop (Shopify, WooCommerce, etc.)
- Build a stock dashboard or reporting tool
- Trigger low-stock alerts and automated reordering
- Route orders to the correct warehouse based on availability
- Audit batch, serial number, and best-before-date data at storage locations
This is a read-only guide. It covers querying stock data. For writing stock (goods receipt, stock movements, stocktaking), see the related resources at the end.
New to the Xentral API? Read first:
- Authentication - Create API Token
- Rate Limiting - Request limits
ERP Context
Important for developers without ERP experience: Stock in an ERP is not a single number. It is a set of different stock figures that reflect the physical reality, outstanding orders, and business rules.
Why "stock" is not just one number
In a typical shop system, you have one stock count per product. In Xentral, the same product can have:
- 50 units physically in the warehouse (physical stock)
- 10 units reserved for existing sales orders (reserved stock)
- 40 units available to sell (sellable stock)
- 15 units across open sales orders that have not shipped yet
- A pseudo stock correction reported back to your shop
These numbers exist because Xentral manages the full order-to-shipment lifecycle. Stock changes happen at different points depending on your Xentral configuration -- not automatically when an order is placed.
What triggers stock changes?
| Event | Stock Impact |
|---|---|
| Sales order created | Stock can be reserved, depending on project settings (auto-reservation). Physical stock stays the same. |
| Delivery note processed (with auto shipping) | Physical stock is reduced. Goods leave the warehouse. Without auto shipping, stock is not reduced automatically -- you need to trigger the stock booking manually or via the shipping process. |
| Goods receipt (purchase order) | Physical stock increases. |
| Production completed | Finished goods stock increases. Component stock decreases as a separate step (retrograde deduction). These are two distinct actions, not one trigger. |
| Return booked in | Physical stock increases. |
| Cycle count / Inventory (Inventur) | Physical stock is adjusted to match the actual count. Can increase or decrease stock. |
| Transfer / Stock sync (3PL, Fulfillment) | Stock is moved between warehouses or synced with external fulfillment providers. |
| Consignment warehouse | Goods physically leave your warehouse (via delivery note) but remain in your stock -- they are booked into the customer's consignment warehouse. |
Key insight: Stock reservation, stock booking, and stock deduction are all separate actions in Xentral. Which ones happen automatically depends on your project settings, logistics process configuration, and whether auto shipping is enabled.
Warehouse hierarchy
Xentral uses a two-level hierarchy:
- Warehouse (Lager) -- a room, building, or logical area
- Storage Location (Lagerplatz) -- a shelf, compartment, or pallet space within a warehouse
Every warehouse must have at least one storage location. Products are stored at specific storage locations, not just "in a warehouse". This matters when you need to know where exactly a product is -- for picking optimization, warehouse routing, or auditing.
Help Center: For general information about warehouse setup in Xentral, see Creating a warehouse structure.
Understanding the Stock Response
The main stock endpoint (GET /api/v1/products/\{id\}/stocks) returns three sections:
1. totals -- Aggregated stock across all warehouses
totals -- Aggregated stock across all warehousesThis gives you the overall picture for the product. All values are summed across all warehouses.
| Field | Description |
|---|---|
physical | Actual quantity physically present across all warehouses. This is the "real" count. |
sellable | Quantity available to commit to new orders. This is typically the number your shop should display. |
reserved | Quantity earmarked for existing sales orders. These units are spoken for but have not left the warehouse yet. |
calculated | Physical minus all open (unshipped) sales order quantities. Shows what will remain after all current orders ship. |
openSalesOrders | Total quantity across all unshipped sales orders for this product. |
pseudo | A manual stock override value. Can be null if not configured. |
correction | A stock correction offset applied at the product level. |
producible | Quantity that could be produced from available components (for BOM/production items). null if no bill of materials. |
The core formula:
Sellable = Physical - Reserved
Warning for JIT (Just-in-Time) products: The
totalssection aggregates stock across all warehouses. For JIT products with components in different warehouses, the totals can be misleading. Example: a JIT product has two components -- one only in Warehouse A, the other only in Warehouse B. The totals will show stock, but you cannot actually sell the product if both components need to ship together from the same warehouse. For JIT products, always check the per-warehouse breakdown.
2. warehouses[] -- Physical stock per warehouse
warehouses[] -- Physical stock per warehouseShows how stock is distributed across warehouses. Useful for multi-warehouse routing (e.g., ship from the warehouse closest to the customer).
Warehouse 1 (Berlin): physical = 30
Warehouse 2 (Munich): physical = 20
-------------
Total physical: 50
3. salesChannels[] -- Per-channel stock adjustments
salesChannels[] -- Per-channel stock adjustmentsLets Xentral report different stock levels to different shops. Each sales channel can have:
pseudo-- A fixed stock override for this channel. If set, report this value instead ofsellable.correction-- An offset added to the stock reported to this channel.
Note: Stock corrections (
correction) exist at two levels: on the product itself (intotals.correction) and per sales channel (insalesChannels[].correction). If you use sales channel corrections, check both.
Endpoints Overview
| What do you want to achieve? | Endpoint | Scope |
|---|---|---|
| "How much stock does product X have?" | GET /api/v1/products/\{id\}/stocks | productStock:read |
| "Where is product X physically stored?" | GET /api/v1/products/\{id\}/storageLocations | product.listWarehouseEntries |
| "What is reserved for product X and why?" | GET /api/v1/products/\{id\}/reservations | No scope required |
| "Which warehouses exist?" | GET /api/v1/warehouses | Check instance settings |
| "What storage locations does warehouse Z have?" | GET /api/v1/warehouses/\{id\}/storageLocations | storageLocation:read |
| "What items are at a specific storage location (with batch/BBD/serial)?" | GET /api/v2/warehouses/\{wId\}/storageLocations/\{sId\}/items | storageItem:read |
Get Stock Totals for a Product
This is the most important endpoint for shop integrations. It returns all stock figures for a single product.
Required Scope:
productStock:read
Request:
curl -s "https://{instance}.xentral.biz/api/v1/products/{productId}/stocks" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": {
"id": "4",
"totals": {
"pseudo": null,
"sellable": 40.0,
"reserved": 10.0,
"correction": 0.0,
"physical": 50.0,
"openSalesOrders": 15.0,
"calculated": 35.0,
"producible": null
},
"warehouses": [
{"id": "1", "physical": 30.0},
{"id": "2", "physical": 20.0}
],
"salesChannels": [
{"id": "1", "pseudo": 10, "correction": -5}
]
}
}How to use this for shop sync:
- Read
totals.sellable-- this is the available-to-promise quantity across all warehouses. - If you use sales channel corrections, find your channel in
salesChannels[]and apply thepseudoandcorrectionvalues. - If you need per-warehouse stock for routing decisions, iterate over
warehouses[].
Note: If both
pseudoandcorrectionarenullfor a sales channel, the channel sees the same stock astotals.sellable.
Get Storage Locations for a Product
Shows which storage locations hold a specific product and how many units are at each location.
Required Scope:
product.listWarehouseEntries
Request:
curl -s "https://{instance}.xentral.biz/api/v1/products/{productId}/storageLocations" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": [
{
"id": "17",
"amount": "25.00",
"product": {"id": "4"},
"storageLocation": {
"id": "1",
"name": "Shelf-A01",
"warehouse": {"id": "1", "name": "Main Warehouse"}
}
}
],
"extra": {
"page": {"number": 1, "size": 10}
}
}When to use this:
- Warehouse operations: finding where to pick a product
- Auditing: verifying that stock distribution matches expectations
- Reporting: showing stock distribution across locations
Note: The
amounthere is the physical quantity at each location. It does not account for reservations. This endpoint does not include quality control attributes (batch, BBD, serial numbers) -- use the Items at a Storage Location endpoint for that level of detail.
Get Reservations for a Product
Shows which sales orders have claimed stock for a product. This helps you understand why sellable might be lower than physical.
No scope required for this endpoint.
Request:
curl -s "https://{instance}.xentral.biz/api/v1/products/{productId}/reservations" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": [
{
"id": "17",
"amount": "25.00",
"reason": "Sales order SO-2024-001",
"project": {"id": "1"}
}
]
}When to use this:
- Debugging: "Why does the product show 50 physical but only 25 sellable?"
- Dashboard: Showing a breakdown of where stock is committed
- Alerting: Detecting when reservations consume most of the available stock
Important: Reservations in Xentral are not on warehouse level. A reservation says "10 units are reserved for this order" but does not tell you which warehouse they will be picked from. This means you cannot calculate sellable stock per warehouse by subtracting reservations from per-warehouse physical stock.
Note: Whether reservations are created automatically when a sales order is placed depends on the project settings (auto-reservation). In some configurations, reservations must be created manually.
List Warehouses
Discover which warehouses exist in the Xentral instance. This gives you the warehouse IDs needed for subsequent calls.
Request:
curl -s "https://{instance}.xentral.biz/api/v1/warehouses" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": [
{
"id": "1",
"designation": "Hauptlager",
"project": null
}
],
"extra": {
"page": {"number": 1, "size": 10},
"totalCount": 1
}
}Key fields:
id-- The warehouse ID you will use in other endpoints.designation-- Human-readable warehouse name.project-- If set, this warehouse is associated with a specific project.
Note: Xentral has two different warehouse concepts: preferred warehouses (set on the sales order to prefer a specific warehouse for fulfillment) and project warehouses (exclusively assigned to a project). The
projectfield on a warehouse indicates a project warehouse. The behavior of project warehouses with stock visibility depends on your instance configuration.
Filter by designation:
curl -s "https://{instance}.xentral.biz/api/v1/warehouses?filter[0][key]=designation&filter[0][op]=equals&filter[0][value]=Hauptlager" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"List Storage Locations in a Warehouse
Lists all storage locations within a specific warehouse. Use it to discover location IDs for the items endpoint or to understand a warehouse's layout.
Required Scope:
storageLocation:read
Request:
curl -s "https://{instance}.xentral.biz/api/v1/warehouses/{warehouseId}/storageLocations" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": [
{
"id": "1",
"warehouse": {"id": "1"},
"designation": "Lagerplatz1",
"description": "",
"project": null,
"sort": 0,
"isReplenishmentLocation": false,
"isConsumptionLocation": false,
"isRestrictedLocation": false,
"productionAccess": false,
"isPosLocation": false,
"abcCategory": "",
"dimensions": {"length": 0, "width": 0, "height": 0}
}
],
"extra": {
"page": {"number": 1, "size": 10},
"totalCount": 1
}
}Key fields:
id-- Storage location ID, needed for the items endpoint.designation-- Human-readable location name.sort-- Sorting number that defines the physical walking order for picking optimization.isReplenishmentLocation,isConsumptionLocation,isRestrictedLocation,productionAccess,isPosLocation-- Boolean flags indicating the location type. See Storage Location Types.dimensions-- Length, width, height for capacity planning.
Get Items at a Storage Location
The most detailed endpoint. Returns the actual items stored at a specific storage location, including batch numbers, best-before dates, and serial numbers. This is a V2 endpoint.
Required Scope:
storageItem:read
Request:
curl -s "https://{instance}.xentral.biz/api/v2/warehouses/{warehouseId}/storageLocations/{storageLocationId}/items" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": [
{
"productId": "1",
"sku": "ABC-12345-S-BL",
"quantity": 5,
"qualityControlAttributes": [
{
"quantity": 5,
"batch": "Batch1",
"bestBeforeDate": "2025-01-01",
"serialNumbers": [
{"number": "001"}
]
}
]
}
],
"extra": {
"totalCount": 1,
"page": {"number": 1, "size": 10}
}
}Key fields:
productId-- The product at this location.sku-- The product's SKU / article number.quantity-- Total quantity of this product at this location.qualityControlAttributes[]-- Detailed breakdown by batch, BBD, and serial numbers.
When to use this -- specifically for quality control attributes:
- Food/pharma: Checking expiration dates for FIFO picking
- Regulated products: Auditing batch traceability
- Electronics/high-value goods: Verifying serial number inventory
Important: You need both the warehouse ID and storage location ID to call this endpoint. Use List Warehouses and List Storage Locations to discover these IDs first. Be aware that querying quality control attributes requires calling this endpoint for every storage location individually -- this can result in many API calls for large warehouses. Consider whether you actually need this level of detail before building a polling strategy around it.
Common Integration Patterns
Pattern 1: Stock Sync to Shop
The most common use case. Periodically sync stock levels from Xentral to your online shop.
+----------+ Poll periodically +----------+ Update stock +----------+
| Xentral | ------------------> | Your | -------------->| Shop |
| API | GET products/ |Middleware| | (e.g. |
| | {id}/stocks | | | Shopify) |
+----------+ +----------+ +----------+
Recommended approach:
- Maintain a list of product IDs to sync (your product catalog mapping).
- For each product, call
GET /api/v1/products/\{id\}/stocks. - Use
totals.sellableas the available quantity. - If using sales channel corrections, check
salesChannels[]for your channel'spseudo/correction. - Update your shop's stock level.
Best Practice: For large catalogs, batch your API calls and respect rate limits. Process the most critical products (best sellers, low stock) first.
Pattern 2: Low-Stock Alerting
Monitor stock levels and trigger alerts when stock falls below a threshold.
What to monitor:
totals.sellabledropping below a minimum thresholdtotals.sellableapproaching zero whiletotals.openSalesOrdersis high (demand exceeding supply)totals.reserved / totals.physicalratio exceeding 80% (most stock is committed)
Pattern 3: Multi-Warehouse Order Routing
When you have multiple warehouses, route orders to the warehouse that has stock.
# Get stock with per-warehouse breakdown
curl -s "https://{instance}.xentral.biz/api/v1/products/{productId}/stocks" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
# Check warehouses[] array for physical stock per warehouse
# Route order to warehouse with highest stock or closest to customerImportant: The
warehouses[]array only shows physical stock per warehouse -- not sellable. Since reservations in Xentral are not tracked on warehouse level, you cannot calculate per-warehouse sellable stock. For most routing decisions, physical stock per warehouse is sufficient.
Pattern 4: Batch/BBD Compliance Check
For food, pharmaceuticals, or regulated products, verify that items in stock are within their best-before dates.
# 1. Find storage locations for a product
curl -s "https://{instance}.xentral.biz/api/v1/products/{productId}/storageLocations" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
# 2. For each storage location, get item details with BBD
curl -s "https://{instance}.xentral.biz/api/v2/warehouses/{warehouseId}/storageLocations/{storageLocationId}/items" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
# 3. Check qualityControlAttributes[].bestBeforeDate for expirationStorage Location Types
Storage location types affect which stock is available for order fulfillment.
| Type | API Flag | Description |
|---|---|---|
| Normal | All flags false | Standard storage. Used for all operations. |
| Replenishment | isReplenishmentLocation: true | Safety stock / buffer. Products must be relocated to a normal location before they can be picked. |
| Consumption | isConsumptionLocation: true | Products booked here are removed from stock entirely. Used for scrapping or internal consumption. |
| Quarantine / Blocked | isRestrictedLocation: true | Stock is invisible to logistics. Used for defective returns, locked products, or non-sale items. |
| Production | productionAccess: true | Restricts warehouse to production use. Stock is used for manufacturing, not order fulfillment. |
| POS | isPosLocation: true | Used with Xentral POS system. Online logistics does not access this stock. |
Note: Whether these storage location type settings are fully reflected in the stock figures returned by
GET /products/\{id\}/stocksshould be verified for your specific use case. If your stock sync shows unexpected numbers, check whether products are stored in replenishment, quarantine, or POS locations.
Polling and Rate Limits
Polling Strategy
Xentral does not currently have webhook events that give a complete picture of all stock changes. Some events exist (e.g., storage-item-movement, reservation-changed) but they do not cover all scenarios. In practice, you need to poll.
| Strategy | When to use | Trade-off |
|---|---|---|
| Poll all products periodically | Small catalog (fewer than 1,000 products) | Simple but uses many API calls. Poll every 5-15 minutes. |
| Poll only changed products | Large catalog, you track which products had orders/shipments | Fewer API calls but requires order event tracking on your side. |
| Full sync on schedule | Nightly reconciliation | Reliable baseline. Combine with frequent polling for critical products. |
Warning: Stock synchronization with large product catalogs will hit rate limits. If you have thousands of products, you cannot poll all of them every few minutes. Prioritize high-turnover products and use longer intervals for slow-moving items.
Rate Limiting
Monitor the X-RateLimit-Remaining header. Rate limits vary by customer instance.
| Remaining | Recommended Action |
|---|---|
| Above 50% | Full speed (no delay) |
| Below 50% | Add a small delay (e.g., 50ms) between requests |
| Below 25% | Add a larger delay (e.g., 200ms) between requests |
Tip: Implement exponential backoff on
429responses. Wait for the time indicated in theRetry-Afterheader before retrying.
Caching Recommendations
| Data | Cache? | Reason |
|---|---|---|
| Warehouse list | Yes, refresh daily | Warehouses rarely change. |
| Storage location list | Yes, refresh daily | Storage locations rarely change. |
| Stock totals | Cache briefly (1-5 min) | Stock changes with every order and shipment. |
| Quality control attributes (batch/BBD/serial) | Decide per use case | Querying this data requires calling the items endpoint for every storage location individually, which is expensive in API calls. Only poll this if you actually need batch/serial level detail. |
Error Handling
| Status | Meaning | Common Cause |
|---|---|---|
| 400 | Bad Request | Invalid query parameters or filter syntax |
| 401 | Unauthorized | Invalid or expired token |
| 403 | Forbidden | Missing required scope (e.g., productStock:read) |
| 404 | Not Found | Product ID, warehouse ID, or storage location ID does not exist |
| 406 | Not Acceptable | Missing Accept: application/json header |
| 429 | Too Many Requests | Rate limit exceeded |
Note: Xentral returns
400 Bad Requestfor validation errors, not422. TheAccept: application/jsonheader is mandatory on every request -- without it you get a406error.
Pagination
All list endpoints support page-based pagination.
# First page, 50 items per page
curl -s "https://{instance}.xentral.biz/api/v1/warehouses?page[number]=1&page[size]=50" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response pagination metadata:
{
"data": ["..."],
"extra": {
"page": {"number": 1, "size": 10},
"totalCount": 47
}
}Use totalCount to determine how many pages you need: ceil(totalCount / page[size]).
Related Resources
API Documentation
- View Product Stocks
- Product Storage Locations
- Product Reservations
- List Warehouses
- List Storage Locations
- List Storage Location Items (V2)
- Authentication
- Rate Limiting
Help Center
- Creating a warehouse structure - Warehouse setup and stock calculation
- Selection and settings of the logistics process - Logistics processes, auto reservation
- Best before date (BBD) - BBD registration and management
- Stock movement types - Inbound, outbound, and relocation movements
- 3PL: Preparatory settings - Available quantity formula for fulfillment integrations
Related Guides
- G1: Create Sales Order - Create orders that reserve stock
- G2: Create Customer - Create customers for orders
- G3: Create Product - Create products that can be stocked
Updated 1 day ago