How to Flag Adobe Commerce Products That Are Out of Stock at Every Source
Build a Spojit workflow that runs on a schedule, checks your Adobe Commerce source items for products with zero salable stock at every inventory source, and posts a prioritized alert to Slack.
What This Integration Does
With Adobe Commerce Multi Source Inventory (MSI), a single product can hold stock at many sources (warehouses, stores, drop-ship locations). A product is only truly unsellable when it has run dry at every source that feeds its stock. Spotting those products by hand means opening each SKU and reading source quantities one row at a time, which does not scale across a large catalog. This workflow does that scan for you on a fixed cadence and surfaces only the products that have nothing salable left anywhere, so your merchandising team can reorder, hide, or substitute them before customers hit an out-of-stock page.
The workflow is started by a Schedule trigger on a cron you choose (for example every morning before the store gets busy). On each run it pulls the active product list from Adobe Commerce, inspects the source items behind each SKU, asks Miraxa, the intelligent layer across your automation, to confirm and rank the genuinely zero-stock products, and posts a single grouped message to a Slack channel. It writes nothing back to your store and holds no state between runs: each run is a fresh snapshot, so re-running it is always safe and simply produces the latest picture.
Prerequisites
- An Adobe Commerce REST connection in Spojit with an integration token that can read products and the
inventory/source-itemsendpoint. See Understanding Connectors and Connections if you have not added one yet. - A Slack connection authorized to post to the channel you want alerts in. The connector needs scope to read channels and send messages.
- The Slack channel ID or name you will post to (for example
#inventory-alerts). - Multi Source Inventory enabled in Adobe Commerce so that source items exist per SKU.
Step 1: Start with a Schedule trigger
On a new workflow, add a Trigger node and set its type to Schedule. Enter a 5-field Unix cron expression and an IANA timezone so the run lands at the right local hour. For a weekday 7am sweep in Sydney:
Cron: 0 7 * * 1-5
Timezone: Australia/Sydney
A single Schedule trigger can hold more than one schedule, so you can add a second entry (for example a midday re-check) later. The trigger output is { scheduledAt }, which you can reference downstream as {{ trigger.scheduledAt }} to stamp the alert.
Step 2: List active products from Adobe Commerce
Add a Connector node in Direct mode, choose the Adobe Commerce REST connector, and select the list-products tool. Restrict the scan to sellable, in-catalog products so you do not flag disabled items:
status: 1 (enabled)
typeId: simple
pageSize: 100
currentPage: 1
sortField: sku
sortDir: ASC
The result is a paginated envelope of products including each sku, name, and status. Reference the list downstream as {{ list_products.items }} (bind the node output to a variable such as list_products in its settings).
Step 3: Fetch source items per product with a Loop
Add a Loop node in ForEach mode and point it at the product list from Step 2. Inside the loop body, add a Connector node in Direct mode using the Adobe Commerce REST connector and the get-source-items tool, filtered to the current SKU:
sku: {{ item.sku }}
pageSize: 50
This returns the inventory source items for that SKU across every source, each carrying a quantity and a per-source stock status. A product is a candidate for flagging when every returned source item has a quantity of 0 and is not in stock. Keep the loop body lean: one source-items call per SKU is all this step needs.
Step 4: Confirm salability with check-product-salability
Source quantities alone can lie when reservations or backorder rules are in play, so confirm each candidate. Still inside the loop, add a Condition node that only proceeds when the candidate has zero quantity at all sources, then add a Connector node in Direct mode with the Adobe Commerce REST connector and the check-product-salability tool:
sku: {{ item.sku }}
stockId: 1
Use 1 for the default stock unless your store assigns SKUs to a different stock. A product that returns not salable here is genuinely out of stock everywhere. Collect each confirmed SKU, name, and its source breakdown into a running list (a Transform node is handy for shaping each match into a compact object like { sku, name, sources }) so the next step receives one clean array, for example {{ zero_stock.items }}.
Step 5: Prioritize the list with Miraxa in Agent mode
Add a Connector node in Agent mode pointed at the Slack connector and define a Response Schema so the output is reliable JSON. Pass the confirmed list in the prompt and let the intelligent layer rank which products matter most (for example bestsellers or those with the most affected sources) and write a short, channel-ready summary. A prompt like the following works well:
Here is a list of Adobe Commerce products that have zero salable stock
at every inventory source: {{ zero_stock.items }}.
Rank them from most to least urgent to restock, give a one-line reason
each, and produce a concise Slack message grouped by urgency.
Look up the channel ID for #inventory-alerts before sending.
Force the shape with a Response Schema such as:
{
"type": "object",
"properties": {
"summary": { "type": "string" },
"channelId": { "type": "string" },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sku": { "type": "string" },
"name": { "type": "string" },
"urgency": { "type": "string" },
"reason": { "type": "string" }
}
}
}
}
}
In Agent mode the connector can call Slack tools such as list-channels to resolve the channel before composing the message. Bind the output to {{ rank }}.
Step 6: Post the prioritized alert to Slack
Add a final Connector node in Direct mode using the Slack connector and the send-message tool to post the formatted result:
channel: {{ rank.channelId }}
text: Zero-stock-everywhere report for {{ trigger.scheduledAt }}
{{ rank.summary }}
If you prefer to skip Agent mode, you can build the message text directly from {{ zero_stock.items }} with a Transform node and still post it with send-message. To notify a specific person rather than a channel, use the Slack lookup-user-by-email tool to resolve their user ID first, then send to that ID.
Tips
- Page through the catalog:
list-productsreturns one page at a time. For large stores, raisepageSizeand incrementcurrentPageuntil you have collected every SKU before the loop, or wrap the listing in its own pagination loop. - Keep the per-SKU work cheap.
get-source-itemsruns once per product, so a Direct-mode call (no AI cost) inside the loop keeps the run fast and predictable; reserve Agent mode for the single ranking step. - If most of your catalog sits at one warehouse, filter
get-source-itemsbysourceCodefirst to shrink results, then fall back to the full scan only for SKUs that look empty. - Add a second schedule to the trigger (for example a midday re-check) instead of duplicating the workflow.
Common Pitfalls
- Zero quantity is not the same as unsellable. Backorders, reservations, and stock thresholds can keep a product salable at 0, which is why Step 4 confirms with
check-product-salabilitybefore flagging. - Wrong
stockId. The default is1; if your store maps SKUs to non-default stocks, the salability check returns misleading results. Confirm your stock assignment in Adobe Commerce. - Timezone drift. The Schedule trigger uses the IANA timezone you set, not the store timezone. If the alert lands at an odd hour, check the trigger timezone against your Adobe Commerce locale via
get-store-config. - Slack channel access.
send-messagefails silently to private channels the connection has not been invited to. Invite the Slack app to the target channel first.
Testing
Before scheduling it live, narrow the scope and run once. Set list-products to a small pageSize (or add a sku filter for a product you know is empty everywhere) and point the final send-message at a private test channel. Use the Run button or temporarily switch the trigger to Manual, then inspect the execution log to confirm the source-items and salability calls returned what you expect and that the Slack message lists the right SKUs. Once the small-scope run looks correct, restore the full catalog scope, set the real channel, and let the schedule take over.