Skip to main content

POS Sync

FREE!

Real-time POS sync in minutes.

Keep your online store's inventory in step with sales rung up at the till — a provider-agnostic bridge between any point-of-sale (Square, Clover, Zettle, Lightspeed) and any WordPress store (WooCommerce, FluentCart, SureCart, Easy Digital Downloads, Ecwid). Real-time stock sync, free.

POS Sync keeps an online store in step with the physical shop. When a customer buys the last blue hoodie at the counter, the website should stop selling it — within seconds, without anyone touching WordPress.

That sounds like one integration. It is really two independent problems, and the whole design follows from keeping them apart:

  • Which till? Square, Clover, Zettle, Lightspeed, or a shop's own bespoke software.
  • Which store? WooCommerce, FluentCart, SureCart, Easy Digital Downloads, Ecwid.

:::info Status — 1.1.0, roadmap complete The ledger is built (schema, idempotency, the event-time-ordered queue, retries, the audit log), so is the store driver seam with WooCommerce on the end of it, and so is the signed webhook API — which means a real till can feed the ledger today. Any POS with outbound webhooks, any middleware, or a shop's own software can post to it. 346 assertions cover them, needing neither hardware, a Square account, nor — for most of them — a cart.

The Virtual Terminal is built, so all of it can be exercised and demonstrated with no hardware at all — twelve adversarial scenarios, each checking its own expectation. And the first-party Square driver now ships: OAuth, webhooks, catalog import and location mapping.

Reconciliation and the operational layer are built too: a nightly sweep that asks the POS what it thinks the numbers are, an authority policy for who owns which field, and a health dashboard whose alarm is silence — because a till that stops sending does not throw, it just goes quiet while stock drifts.

The roadmap is complete. Three of the expansion drivers — FluentCart, SureCart and Clover — are marked experimental: they were written against documented APIs with no live install to verify against, so each refuses to activate unless every function it calls is actually present. A wrong assumption disables the driver; it cannot quietly write wrong stock. If one does not work for you, the Health screen produces a diagnostic report that is safe to paste in public.

The rest of this section is the design of record: the architecture, the wire format, and the build order. The Roadmap tracks progress and updates itself from the extension source — see How this page stays current.

Source: UnysonPlus-POS-Sync-Extension :::

Why it is its own extension

It would be natural to add this to the WooCommerce extension. That turns out to be the expensive choice.

With N POS providers and M e-commerce plugins, POS logic living inside a Woo-specific extension means every provider driver has to be rewritten to add a second cart — N×M work. Put a normalized ledger in the middle instead, and each side only has to know about that ledger: N+M.

Square ─┐ ┌─ WooCommerce
Clover ─┤ ├─ FluentCart
Zettle ─┼─► POS drivers ─► LEDGER ─► store ──┼─ SureCart
Any │ drivers ├─ EDD
webhook ─┘ └─ …

The ledger is the canonical, cart-agnostic record of what happened in the shop: an item, a sale, a refund, a stock movement. POS drivers only write to it. Store drivers only read from it. Neither side knows the other exists.

Three practical consequences follow:

  • Scope stays clean. The WooCommerce extension is about storefront integration. POS sync is background jobs, webhook endpoints, HMAC secrets, reconciliation and an audit log — a different concern, and one that shouldn't load for every Woo user who will never own a till.
  • The hard problems are cart-agnostic anyway. Idempotency, out-of-order offline batches, refund restocking, location mapping — none of that is WooCommerce-shaped. Coupling it to wc_update_product_stock() buries generic logic inside one vendor's API.
  • Activation is independent. A FluentCart shop shouldn't need the WooCommerce extension active.

→ The full reasoning, including the trade-offs considered, is in Architecture.

What ships first

Deliberately narrow. POS integrations are maintenance-heavy — every vendor is bespoke and their APIs move — so version 1 is one generic surface plus one polished driver, not five half-drivers.

WhatWhy first
1Generic webhook APIAny POS with outbound webhooks, any middleware (Zapier / Make / n8n), or a shop's own till software can push to it. You ship a spec, not an integration — nothing to break when a vendor changes their API.
2Virtual TerminalFires realistic synthetic sales at your own endpoint. Development test rig, customer pre-launch check, and live demo, all in one screen.
3WooCommerce store driverThe largest install base, and the reference implementation of the store seam.
4Square provider driverBest free sandbox, cleanest API, biggest small-retail share. Proves the provider seam.

Everything else — FluentCart, SureCart, Clover, Zettle, Lightspeed — is post-1.0, added on demonstrated demand.

"But I don't own a POS machine"

You don't need one. Every serious POS vendor publishes a free sandbox that emulates the hardware entirely: you create a test seller account, push a sale through their API, and receive the same real webhooks a physical terminal would send.

Add the Virtual Terminal for the cases sandboxes make awkward — duplicate webhooks, out-of-order offline batches, expired signatures — and hardware never enters the picture.

Testing without hardware walks the whole setup, including the tunnel that lets sandbox webhooks reach a local XAMPP install.

The decisions that matter most

These bite harder than any API plumbing. Each is settled here so the implementation doesn't have to re-litigate it:

  • Stock has one owner. The POS is authoritative for stock levels; the store is authoritative for product content — title, description, images, SEO — with a per-product override. Symmetric two-way stock sync with no declared authority produces drift and oversells, reliably.
  • Match on SKU. Always. GTIN/barcode as a fallback. Never on product title.
  • Every event is idempotent. Webhooks get retried; tills reconnect and re-send. The external transaction id sits behind a UNIQUE index, so a replay is recorded and dropped, never applied twice.
  • Apply by event time, not arrival time. An offline till dumps its batch late and out of order. Ordering by arrival lets a stale sale overwrite a newer count.
  • Refunds, voids and partial returns restock. This is where cheap integrations fall over.
  • Locations are explicit. Each POS location maps to a stock source, or the site declares single-store mode. Never left implicit.
  • Architecture — the ledger, the two driver seams, and the data model. Start here.
  • Roadmap — what's built, what's next, verified against the source tree.
  • The webhook API — endpoints, signing, and the normalized payload schema.
  • Store drivers — the FW_POS_Store interface and each cart's notes.
  • Square — connecting Square, sandbox to production, step by step.
  • Testing without a POS — sandbox, tunnel, Virtual Terminal, automated suite.
  • Troubleshooting — when stock is wrong and you need to know why.