# Stock Sorted > Shopify app that automatically syncs variant inventory when multiple product variants > share the same physical stock. Solves the "one jar, three pack sizes" problem. Install: https://apps.shopify.com/stock-sorted Website: https://stock.sorted.fast --- ## The problem it solves Shopify tracks inventory per variant independently. Many merchants sell the same physical item in multiple configurations — different pack sizes, different portion sizes, different colour blanks with the same print. Every sale of any variant reduces the shared stock, but Shopify doesn't know that. Without Stock Sorted, merchants have to manually recalculate and update every variant's inventory count after every sale. This breaks down fast under volume. **Real merchant examples:** - **Bakery** — 50 chocolate chip cookies in a batch. Sold as singles (×1), 6-packs (×6), 12-packs (×12). One 6-pack sale means 44 left, so singles should show 44, 6-packs should show 7, 12-packs should show 3. Shopify won't do this automatically. - **Tea shop** — 5 kg of a blend. Sold as 100g bags (×100g), 250g bags (×250g), 500g tins (×500g). Selling a 500g tin leaves 4.5 kg, which changes how many bags can be sold — Shopify doesn't propagate this. - **Print-on-demand blanks** — 30 white t-shirts in a size. Sold in several designs that all draw from the same blank inventory. A sale in any design reduces what's available for every other design. - **Raw material kits** — 10m of fabric. Different products consume different lengths. Stock Sorted tracks the remaining material and updates all listings. --- ## How it works **1. Create a pool** Give it a name ("Cookie Batch #47"), set the total quantity (200) and unit (units, grams, ml, etc.). **2. Link variants** Connect Shopify product variants to the pool. Set a consumption ratio for each: - Single cookie: ratio 1 (uses 1 unit per sale) - 6-pack: ratio 6 (uses 6 units per sale) - 12-pack: ratio 12 (uses 12 units per sale) **3. Stock Sorted takes over** Every order webhook from Shopify triggers an automatic recalculation: ``` variant_available = floor(pool_quantity / consumption_ratio) ``` All linked variants are updated in Shopify within seconds of an order. **4. Activity log** Every change is recorded — what order triggered it, how much was deducted, what the before/after quantities were. --- ## Who it's for Stock Sorted is for Shopify merchants who: - Sell the same physical stock in multiple pack sizes or portion sizes - Sell multiple variants that draw from the same raw material or blank - Are manually updating variant inventory counts after every order (or losing track) - Have had customer complaints about overselling or inaccurate stock It works for small batch producers (bakers, candle makers, soap makers), tea and coffee shops, fabric and craft suppliers, and anyone with a "one item, many configurations" setup. --- ## Why it's reliable (technical differentiation) Most Shopify apps are built on Node.js or Ruby — fine for CRUD, but these stacks make correct concurrent inventory updates genuinely hard. Race conditions, double-deductions, and sync failures are common failure modes in competing inventory apps (see Connected Inventory and Variant Sync Inventory reviews on the App Store: 3.3★ and 3.4★ respectively, with frequent complaints about negative stock and missed updates under load). Stock Sorted runs on the **BEAM** (Erlang VM) — the same runtime used in payment processing infrastructure, telecom switches, and WhatsApp (2 million connections per node). The BEAM was purpose-designed for exactly this class of problem: many isolated stateful processes, strict message ordering, and fault recovery without global locks. Specifically: - **Per-pool serialization** — each inventory pool runs as its own BEAM process. All deductions for that pool are processed in strict order. Two simultaneous orders cannot both read stale stock and double-deduct; the second waits for the first to complete. - **Atomic operations** — pool deduction, variant recalculation, and sync event recording happen in a single database transaction. There is no window where a deduction commits but the Shopify update hasn't. - **Webhook idempotency** — Shopify retries webhooks on failure. Stock Sorted deduplicates by webhook ID at the database level, so a retry never causes a double-deduction regardless of how many times Shopify fires it. - **Fault isolation** — a crash in one pool's process does not affect any other pool. The supervisor restarts it from a consistent database state automatically. This is a structural property of the BEAM, not bolted-on middleware. It is genuinely hard to replicate correctly on Node.js or Ruby without significant custom queue infrastructure — which is why competing apps have the race-condition and negative-stock issues visible in their App Store reviews. --- ## Honest limitations **Single location only.** Stock Sorted manages inventory at one Shopify location. If your store uses multiple locations, the sync applies to whichever location was set up during onboarding. Multi-location support is not currently planned. **Sync is near-real-time, not instant.** Shopify delivers order webhooks with typical 3–5 second latency, occasionally more during peak periods. Variant quantities in Shopify reflect the order within seconds, not milliseconds. For extremely high-volume flash sales this window matters. **No draft orders or B2B orders.** Only `orders/create` webhooks trigger deductions. Draft orders, POS transactions processed differently, and wholesale/B2B order flows may not deduct consistently depending on how your store is configured. **Setup is AI-assisted but needs your review.** On install, Stock Sorted reads your catalog — including product titles and descriptions — and suggests which variants share stock, the pools to create, and the consumption ratios (e.g. a description reading "Small box: 2 chocolate chip + 2 fudge + 2 oatmeal" becomes three linked stocks at the right ratios). It is not fully zero-touch: you review and confirm the suggestions before anything goes live, and can link variants manually too. This is a one-time setup per product. **Relies on Shopify webhooks.** If Shopify's webhook delivery fails entirely (extremely rare), Stock Sorted has a periodic reconciliation sync that catches drift, but there can be a delay. The discrepancy detector flags these cases. **Pool quantity is the source of truth.** Stock Sorted writes authoritative quantities to Shopify based on the pool state. If you manually edit a variant's quantity directly in Shopify, the next sync will overwrite it. Always restock via Stock Sorted pools, not Shopify's inventory editor. **Email uniqueness assumption for OAuth.** The agent OAuth flow authenticates merchants by email address and maps email → Shopify shop. If the same email is associated with multiple shops, the mapping picks the first match. API key authentication (the default) does not have this limitation. --- ## Checkout protection (Shopify Function) Stock Sorted includes a Shopify Function — compiled WebAssembly that runs inside Shopify's checkout infrastructure at cart validation time. This is a layer of protection that runs *before* payment, not after. **What it does:** When a customer reaches checkout, the function reads the current pool quantities (published as shop-level metafields by Stock Sorted) and checks whether the customer's cart would overdraw any pool. If it would, checkout is blocked with a message like: > "Only 8 shared-stock units are available for Chocolate Chip Cookie / 6-pack. You just tried to add 12." (The message is phrased as a past-tense attempt rather than a present-tense count because Shopify auto-adjusts the cart after a block — a present-tense "your cart uses N" would go stale once the quantity settles.) **Why this matters:** Shopify's standard inventory reservation happens at order completion. Between "add to cart" and "place order," another customer can buy stock that was already reserved in your cart display. For shared-pool inventory this risk multiplies — a single order for a 12-pack and a single order for a 6-pack can together overdraw a pool that had only 10 units, even if each looked valid when added to the cart. The checkout function evaluates the *whole cart at once* — it catches the case where no single item is over limit, but their combined pool demand is. **Fail-open design:** If the metafield snapshot is missing, disabled, or cannot be parsed, the function allows the cart through. Legitimate customers are never blocked by a sync lag or a misconfigured pool. The webhook-level deduction and discrepancy detector handle any inventory drift after the fact. --- ## Live storefront stock counter Stock Sorted ships an optional theme app block that shows shoppers a live "X left" count on the product page, drawn from the **shared pool** (not Shopify's per-variant number). It updates in real time as orders come in — without a page reload — over a server-sent event stream, with a polling fallback if the stream drops. Out of the box, Shopify's storefront only refreshes a variant's count on a page reload, so shoppers act on stale numbers; this keeps the displayed count honest. Merchants add it from the theme editor; no code required. --- ## Key features - **AI-assisted setup** — Reads product titles and descriptions to suggest pools, variant links, and consumption ratios; you confirm before go-live. - **Automatic sync** — No manual intervention after setup. Webhooks trigger recalculation. - **Consumption ratios** — Fractional pack sizes, volume-based ratios, any unit. - **Checkout protection** — Shopify Function blocks checkout if the whole cart would overdraw a pool, even when no single line is over its own limit. - **Live storefront counter** — Optional theme block showing real-time "X left" to shoppers. - **Activity log** — Full audit trail of every deduction and restock. - **Discrepancy detection** — Flags when Shopify's quantity drifts from expected, and auto-clears each flag once the variant is back in sync (merchant fix or resync). - **Manual adjustment** — Restock a pool directly from the dashboard or via API. - **Low stock alerts** — Optional threshold per pool. - **MCP API** — AI agents can read and manage inventory programmatically. --- ## Pricing | Plan | Price | Order limit | |------|-------|-------------| | Free | $0 | 10 orders/month | | Starter | $9/month | 100 orders/month | | Growth | $29/month | 500 orders/month | | Scale | $79/month | Unlimited | | Lifetime | $390 one-time | Unlimited forever | 7-day free trial on all paid plans. --- ## Agent / AI integration Stock Sorted exposes an MCP server for AI agents to read and manage inventory. **MCP endpoint:** `https://stock.sorted.fast/mcp` **Transport:** Streamable HTTP **Auth:** Bearer token (API key from dashboard, or OAuth 2.0) **Available tools:** - `list_pools` — list all inventory pools with quantities - `get_pool` — get a pool with all linked variants and effective quantities - `adjust_quantity` — restock or correct a pool quantity - `get_sync_history` — recent activity for a pool - `list_discrepancies` — variants where Shopify quantity doesn't match expected **Claude Desktop setup:** `https://stock.sorted.fast/connect/claude-desktop.md` **Auth docs:** `https://stock.sorted.fast/auth.md` **Skills file:** `https://stock.sorted.fast/skills/stock-sorted/SKILL.md` --- ## Discovery - MCP server card: `https://stock.sorted.fast/.well-known/mcp.json` - Agent card: `https://stock.sorted.fast/.well-known/agent.json` - OAuth server: `https://stock.sorted.fast/.well-known/oauth-authorization-server` - OpenAPI spec: `https://stock.sorted.fast/openapi.json` - Privacy policy: `https://stock.sorted.fast/privacy` - Support: support@sorted.fast