How to Sync Inventory to Adobe Commerce (Magento 2) with the REST API Instead of SOAP

Keep Adobe Commerce (Magento 2) stock levels in step with your ERP or warehouse file by updating inventory source items through the REST API, with no SOAP client and no inventory sync module to install.

What This Integration Does

Many Magento 2 inventory sync guides start with the SOAP API or a paid "inventory sync SOAP module". You do not need either. Magento 2 exposes the same inventory service contracts over REST, and REST is simpler to call, easier to debug and what Spojit's Adobe Commerce REST connector uses. This workflow reads stock levels from your source of truth (a CSV that your ERP or 3PL drops on an SFTP server, in this example), compares them with what Magento holds, and writes only the changes back with one batched call to inventory/source-items, the Multi-Source Inventory (MSI) endpoint.

The workflow runs every 15 minutes. Each run is idempotent: it sets absolute quantities rather than adding or subtracting, so a run that repeats, or two runs that overlap, leave Magento with the same numbers. Products whose quantity has not changed are skipped, which keeps the API load and the reindex work low.

SOAP or REST?

Both reach the same inventory services. The SOAP endpoint for saving source items is the inventoryApiSourceItemsSaveV1 service, published at /soap/default?wsdl&services=inventoryApiSourceItemsSaveV1 on your store. REST reaches it at POST /V1/inventory/source-items with a JSON body. Use SOAP only if an existing system already speaks it; for a new integration, REST needs no WSDL tooling and works with the same integration token.

Prerequisites

  • An Adobe Commerce REST connection in Spojit using an integration access token with access to Catalog and Inventory resources.
  • Your inventory source code. Single-warehouse stores use default; multi-warehouse stores list their sources under Stores -> Inventory -> Sources.
  • A stock feed. This example uses a CSV with sku and qty columns on an FTP / SFTP server, but any source works, such as NetSuite through SuiteQL or a database query.

Step 1: Schedule Trigger

Add a Trigger node with type Schedule and cron */15 * * * *.

Step 2: Read the Stock Feed

Add a Connector node on FTP / SFTP with download-file and path /outbound/stock.csv. Then a Connector node on CSV Tools with parse, header on, to turn it into rows. Name the output feed. Each row is { "sku": "...", "qty": "..." }.

Step 3: Read Magento's Current Quantities

Add a Connector node on Adobe Commerce REST with get-source-items, sourceCode set to your source and pageSize 500, inside a Loop that increases currentPage until a page returns fewer items than the page size. Name the collected list current. Each source item has sku, source_code, quantity and status.

Step 4: Work Out What Changed

Add a Code Runner step with execute-javascript that compares the two lists and returns only changed SKUs in Magento's format:

const current = new Map(data.current.map(i => [i.sku, i.quantity]));
const changed = [];
for (const row of data.feed) {
  const qty = Math.max(0, Number(row.qty));
  if (!current.has(row.sku)) continue;          // unknown SKU: skip, do not create
  if (current.get(row.sku) === qty) continue;   // unchanged
  changed.push({ sku: row.sku, source_code: "default", quantity: qty, status: qty > 0 ? 1 : 0 });
}
return { sourceItems: changed };

Set the step's input to { "feed": {{ feed.items }}, "current": {{ current }} } (copy the exact paths from the earlier steps' output panels); the code reads it as data. Name the output delta; the returned object is in {{ delta.result }}. Setting status to 0 at zero quantity marks the item out of stock at that source.

Step 5: Save the Changes in One Call

Add a Condition that continues only when {{ delta.result.sourceItems }} is not empty, then a Connector node on Adobe Commerce REST with raw-rest-request:

  • method: POST
  • path: inventory/source-items
  • body: {{ delta.result }}

The body is { "sourceItems": [ { "sku", "source_code", "quantity", "status" } ] }. Magento saves the whole batch in one request and returns an empty success response. For very large deltas (thousands of SKUs), split sourceItems into chunks of 500 with the Array Tools chunk tool and save each chunk in a Loop.

Step 6: Report Problems

Collect SKUs that are in the feed but not in Magento (the ones the Code Runner skipped) and, once a day, send them to your merchandising channel with the Slack connector's send-message. They are usually new products waiting to be created, or SKU typos in the ERP.

Tips

  • Stores without MSI: if Multi-Source Inventory modules are disabled, inventory/source-items does not exist. Use the legacy stock item endpoint instead: PUT products/{sku}/stockItems/1 with { "stockItem": { "qty": 25, "is_in_stock": true } }.
  • Salable quantity: what customers can buy is the source quantity minus reservations for unshipped orders. Use check-product-salability to confirm what the storefront will show after a sync.
  • Several warehouses: include one entry per SKU per source_code in the same batch; Magento updates each source independently.
  • Webhook instead of polling: if your ERP can call a URL when stock changes, start this workflow from a Webhook trigger and update only the SKUs in the payload.

Common Pitfalls

  • Quantities as strings: CSV values arrive as text. Convert them to numbers before comparing, or every SKU looks changed on every run.
  • Negative stock in the feed: some ERPs report negative availability. Clamp to zero, as the Code Runner does, or Magento rejects the batch.
  • Indexers on Update on Save: large syncs trigger reindexing. Set the inventory indexers to Update by Schedule so saves stay fast.
  • Store code in the path: the connector sends REST calls to /rest/{storeCode}/V1/ using the store code on the connection. Inventory is global, so use the default store code.

Testing

Put a feed with three SKUs on the SFTP server: one unchanged, one with a new quantity and one set to zero. Run the workflow manually and check Catalog -> Products in the Magento admin: only the second and third should change, and the third should show as out of stock at the source. Then load the full feed and turn the schedule on.

Learn More

Ready to build this?

Start on the free plan: 500 AI credits a month, no card needed.

Start free

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.