Inventory sources and demand planning
Nasam's shared stock pool has a source of truth when a brand has an active warehouse connection or an active D2C seller storefront. The source read requires brandId and returns type (WMS, D2C, or null) plus sourceName. An active WMS wins; an active D2C storefront is next. null means no source was resolved, so a newly connected channel cannot assume a shared pool anchored to one.
The source and the destination are different. A source tells Nasam where pool stock is anchored. A forecast destination can be the main warehouse, a marketplace fulfillment center, or a channel listing that holds its own stock. A product's destinations carry each location's currentUnits, inbound units, velocity, cover, need, and signal. The row's totalGapUnits covers channel destinations; the main warehouse's need stays on its destination to avoid double counting.
Decide where stock belongs
- Read the brand's inventory source before treating a connected channel as part of the shared pool.
WMSmeans an active warehouse connection anchors the pool;D2Cmeans a seller storefront does. Iftypeisnull, investigate the intended source or use channel-specific inventory settings rather than assuming pooled stock. - Read the account's inventory settings.
inventoryScopetells you whether that account participates in the brand pool, tracks its own channel inventory, or is managed outside Nasam. A storefront'sinventoryBranchIdmay select a particular branch. - Read the forecast destinations for the product. Do not sum
totalGapUnitsand the main warehouse need: the latter describes the warehouse's procurement question and is already kept separate from channel transfer gaps.
This distinction matters when deciding whether to order stock, transfer stock to a fulfillment center, or correct a listing quantity. Those are different actions even when they concern the same SKU.
Read the forecast and missing inputs
GET /v1/inventory-planning returns inventoryForecast and pagination. Filter by brandIds, saleChannelIds, search, and signals. search matches SKU, barcode, English name, or Arabic name. Signals include NeedsAction, Excess, RestockWarehouse, Covered, and NoSignal. It defaults to page 1 and limit 25, with a maximum of 100. A saleChannelIds filter keeps a product row if any destination matches; it does not remove the other destinations from that row or change the row's roll-up.
Signal counts use the forecast scope for a summary. Input gaps identify brands or SKUs relying on fallback lead time, shelf life, or holding inputs. A NoSignal destination includes a noSignalReason such as NeverClassified, NeverSold, InsufficientData, or NoActiveListing; it is not zero demand. Stock alerts provide a separate paginated operational view.
Read a product's destination rows before acting on its row-level signal. NeedsAction points to a channel shortfall, RestockWarehouse to the main warehouse, and Excess to more stock than the plan needs. A product row can carry several destinations with different signals; a channel filter retains the complete row for interpretation. NoSignal means the planner cannot make a demand recommendation for that destination, so inspect the reason and input gaps before treating the need as zero.
Set planning inputs
Read planning configuration with brandId to see declared values, defaults, and events. PUT the configuration is a full replacement of the brand's declared knobs: procurement lead time, target cover, fulfillment-center lead time, safety quantile, and seasonal multipliers. Read first and include every declaration you intend to preserve. Null or omitted numeric knobs use planner defaults; an omitted knob is not an unchanged knob. The update replans the brand and returns the resolved configuration. Compare that response with the previous read before assuming a seasonal or safety setting survived.
Product forecast inputs
A product's forecast inputs are its declared weight, dimensions, shelf life, and holding limit. The brand's CSV template, with isPrefilled=true, shows what each product holds today; the CSV upload declares changes. A blank cell leaves the stored value alone. The upload can return row-level errors even on HTTP 201, so inspect its success, validItems, and errors before reporting completion.
Product inputs and brand planning configuration serve different levels. Set a missing product shelf life or holding limit on the product, then re-read its forecast after planning catches up. Use the input-gaps read to find where fallback values still stand in for declared values. Do not use a listing price or stock update to correct a forecast input.
Diagnose drift before a write
The three correction pairs answer different questions:
| If you need to… | Preview | Apply |
|---|---|---|
| Push the existing pool to channel listings | Reconcile preview | Reconcile |
| Anchor the pool to its source truth, then push it | Reanchor preview | Reanchor |
| Re-push only channels whose observed stock differs from the last push | Drift preview | Drift resync |
Every request supplies brandId. Reanchor also accepts shouldReadFromSource: when true, Nasam reads the live storefront or WMS instead of its stored mirror and fails the request if that live read fails. Previews write nothing. A drift preview includes per-channel currentQuantity, newQuantity, and willRaise; a raised channel deserves an order check before applying, because an unrecorded sale could make the lower observed number correct. These writes change quantities, not listing status. Re-read the source, forecast, and Sync Health after an apply.
Correction runbook
- Identify whether the pool is wrong or only its channel copies are wrong. If the pool is trusted, preview reconcile. If a WMS or D2C source is authoritative and the pool must be refreshed from it, preview reanchor. If the issue is a channel read-back that differs from Nasam's last push, preview drift resync.
- Review the preview's affected products and channel quantities. For a drift row with
willRaise: true, check recent orders on that channel before raising available quantity. A lower channel value can reflect a sale Nasam has not captured yet. - Apply only the matching operation after that review. For reanchor with
shouldReadFromSource: true, a live source read failure stops the write; inspect the connection instead of falling back silently to the stored mirror. - Re-read stock and sync state. A successful apply means the correction request ran; confirm the resulting pool and destination values and inspect channel processing before reporting the marketplace quantity as current.
Connect a warehouse source
List connected and available warehouses first. Connect requires a provider and brandIdInWarehouse; credentials or OAuth requirements depend on that provider. A response may include an oauthUrl. For a dashboard-login provider, discovery starts a browser sign-in and returns {accountId,state:"working"}; poll connect status for working, ready, or failed, then update the account as required. For NetSuite, certificate generation returns accountId and certificatePem for the brand administrator to upload; the private key remains server-side. Stock readings show the WMS watermark. Disconnect and remove record have different lifecycle effects; use the operation page before either write.
Only one warehouse account can be active for a brand. Check the current account before starting another connection. After dashboard discovery, wait for ready before using the discovered account details; a failed result needs a corrected sign-in or account update, not an assumption that stock is connected. For NetSuite, the administrator uploads the returned certificate and the account update completes the connection after the required warehouse identifiers are supplied. Re-read the connected warehouses and the brand's inventory source to confirm that WMS is now authoritative.
The stock readings are the last WMS quantities Nasam received, not proof of an immediate live read. If a correction depends on the warehouse's current values, choose shouldReadFromSource: true on both the reanchor preview and the matching apply. Disconnect is reversible; removing the record deletes it even if it is a draft, failed, or already disconnected and requires a new connection from scratch. Recheck the inventory source and affected channel stock after either change.