Skip to main content

Shopify Sync

When Sync to Shopify is enabled on a production order, Synplex pushes inventory adjustments to Shopify when quantities are produced against components. This keeps Shopify's available inventory in sync with production activity managed in Synplex.


Sync Toggle

Each production order has a syncProductionOrderToShopify boolean field.

  • Shop-level default: set in Settings → Sync production orders to Shopify by default. When an order is started and this field is not explicitly set, the backend reads and applies the shop's default automatically — this happens at the point the order transitions to in_progress, not at creation.
  • Per-order: can be set individually on the order before or during creation.
  • Sync only fires while the order is in_progress — changes to quantityProduced on a draft or completed order are not synced.

What Gets Synced and When

Unlike transfer orders, production order sync does not use Shopify's Inventory Transfer API. Instead, it calls Shopify's inventoryAdjustQuantities mutation directly on the available bucket, referencing the production order as the ledger document.

Sync fires when quantityProduced is updated on a component while the parent order is in_progress and syncProductionOrderToShopify is true.

Each quantityProduced change produces two types of adjustment:

Mutation typeTargetDelta direction
ADJUST_AVAILABLE_OUTPUTFinished-goods output variantPositive — stock increases as units are produced
ADJUST_AVAILABLE_COMPONENTEach BOM component variantNegative — components are consumed during production
For disassembly orders the directions reverse: the output variant stock
decreases and component variants increase as units are disassembled.

If a BOM or BOM component has no inventoryItemId, that leg of the adjustment is skipped and a warning is logged — the rest of the batch still processes.


Deduplication Window

Multiple quantityProduced changes landing within the same 5-second window are collapsed into a single background job execution. The pending sync logs written during that window are all processed in one batch when the job runs, rather than firing a separate Shopify API call per save.

This prevents API rate limit pressure when a user saves several component quantity updates in quick succession.


Sync Guards

Before any adjustment is dispatched, Synplex checks:

  1. Parent production order status must be in_progress — if not, sync is skipped entirely
  2. syncProductionOrderToShopify must be true on the parent order — if false, a SKIPPED log is written and no Shopify call is made
  3. Both inventoryItemGid and locationGid must be present on the pending log — if either is missing, the log is permanently marked FAILED and cannot be retried

Queue and Retry Behaviour

All production order sync mutations run through a background job queue:

SettingValue
Queue nameshopify-production-sync-{shopId}
Max concurrency1 per shop
Retry count3
Initial interval60 seconds
Backoff factor
Max interval5 minutes
JitterYes
Dedup window5 seconds
On the final retry attempt, a failed log is permanently marked FAILED.
Remaining logs in the same batch continue processing regardless — one
failed adjustment does not abort the rest.

Sync Log (productionOrderSyncLog)

Every sync attempt — pending, skipped, successful, or failed — is recorded as a productionOrderSyncLog entry. Log fields include:

FieldDescription
statusPENDING, SUCCESS, FAILED, SKIPPED
triggerTypeWhat caused the sync (PRODUCTION_UPDATED, MANUAL_RESYNC, ORDER_COMPLETED)
mutationTypeThe adjustment type (ADJUST_AVAILABLE_OUTPUT, ADJUST_AVAILABLE_COMPONENT, SKIPPED)
deltaInteger quantity adjustment sent to Shopify
previousQuantityProducedThe component's quantityProduced value before the change
inventoryItemGidShopify GID of the inventory item adjusted
locationGidShopify GID of the location where the adjustment was applied
referenceDocumentUriLedger reference back to the production order (gid://{appHandle}/ProductionOrder/{id})
shopifyAdjustmentGroupIdThe Shopify adjustment group ID returned on success
errorMessageError detail if the attempt failed
retryCountNumber of retry attempts made

How This Differs from Transfer Sync

Production Order SyncTransfer Order Sync
Shopify APIinventoryAdjustQuantities (available bucket)Inventory Transfer API
TriggerquantityProduced change on a componentStatus transitions and shipment events
Sync timingWhile order is in_progressOn confirmation, shipment creation, and receipt
Dedup window5 seconds — rapid saves batchedNo dedup — each event fires independently
Queue concurrency1 per shop2 per shop
Header field syncNot applicablereference and notes on update
Cancellation syncNo Shopify call on cancelTRANSFER_CANCEL mutation if synced