Published 2026-06-11
From n8n to SamePoints — building Shopify + Square loyalty
How we built omnichannel loyalty for a Melbourne pet retailer — Docker, n8n, Postgres, metafields, webhooks, and why gift cards beat discount codes.
By Lance · Founder, SamePoints (Shopify + Square loyalty)
Short answer: SamePoints began as a Docker + n8n + Postgres integration for Pikapet — a premium Melbourne pet retailer on Shopify online and Square in-store. Points are earned from payment and refund webhooks, stored in Postgres, displayed via Shopify customer metafields, and redeemed as Shopify gift cards — not discount codes — because checkout and shipping apps break otherwise.
This is the operator-level architecture story behind the product. No magic — a lot of edge cases.
The business problem (why we bothered)
Pikapet started on Shopify. A physical store followed; Square was the POS that made sense in Australia at the time. Inventory sync apps existed. Loyalty did not.
In-store shoppers asked weekly: "Do you have a membership?" The team could only say online-only. People walked away.
Alternatives we evaluated:
| Option | Issue |
|---|---|
| Square Loyalty | Separate program, paid subscription, no Shopify balance |
| Smile (Shopify) | Free tier with order limits; still no Square earn |
| Spreadsheet / manual | Does not scale past one busy Saturday |
So we built our own pipe — first in n8n, then as SamePoints (2026).
Version 1 architecture: Docker, n8n, Postgres
Shopify webhooks ──┐
├──► n8n workflows ──► Postgres (source of truth)
Square webhooks ──┘ │
├──► Shopify Admin API (metafields)
└──► Gift card create at threshold
Stack on a single host:
- n8n — orchestration, branching, retries, human-readable flows
- Postgres — ledger, customer links, idempotency keys
- Docker — reproducible deploys
Where do points live?
Postgres is the system of record. Shopify customer metafields are the display layer for the theme wallet and logged-in experience.
Why not metafields only?
- Square events do not write to Shopify by themselves
- You need refund history, audit, and duplicate detection Postgres handles better
- Metafields are a sync target, not a database
We sync loyalty.total_points (namespace configurable) after every earn or refund adjustment.
How sync works (earn and reverse)
Shopify
Listen to order webhooks — primarily orders/paid and refunds/create.
- Parse eligible line items (skip gift-card-only payments where configured)
auditable_amount × points_per_dollar→ integer points- Upsert customer (email / phone / Shopify customer id)
- Insert ledger row with
order_referencefor idempotency - Update balance → push metafield
Square
Listen to payment.updated (completed) and refund events — not Square Loyalty API.
- Resolve customer by phone, email, or prior link
amount_aud × points_per_dollar- Same ledger + metafield sync when a Shopify customer link exists
Operator note: If Square Loyalty is also enabled, the same payment can earn twice. Turn off Square Loyalty when using SamePoints. See POS vs Square loyalty.
Why gift cards for redemption (not metafield checkout)
Shopify checkout cannot pay with a custom metafield points balance. You cannot set a product price to $0 dynamically from metafields for arbitrary redemption.
Practical options we considered:
| Approach | Verdict |
|---|---|
| Metafield points at checkout | Not supported natively |
| $0 loyalty "product" | Fragile, breaks catalog and reporting |
| Gift card | Native checkout, stored value, clear balance |
| Discount code | See next section |
At threshold we create a Shopify gift card, deduct points, append to wallet metafield JSON for the theme launcher.
More on psychology and margin: gift cards vs discount codes.
Why not discount codes?
We tried amount-based discount codes for redemption. They conflicted with shipping apps (free-shipping rules, third-party checkout extensions). Carts that should qualify for free shipping failed to calculate correctly.
Gift cards apply as payment instrument, not a competing discount stack — fewer clashes with Shopify Functions and legacy shipping apps.
Other problems we hit (the "complex" part)
Building the happy path is a weekend. Production is months of detail:
Identity and matching
- Australian phone formats (
04xx,+61, spaces) - Same person, Square-only profile + Shopify account → duplicate merge
- Square payment with no phone on terminal → skip or link later
Refunds and mixed payments
- Partial refunds → proportional point reversal
- Orders paid partly with gift card → earn only on non-gift-card portion
- Idempotency: never double-credit the same
order_reference
Reliability
- Webhooks arrive late, duplicate, or fail
- Scheduled Shopify order reconcile catches missed
orders/paid - Retry queue for failed integration events
Display
- Register metafield definitions before first sync
- Theme Rewards launcher reads metafields — Square Customer Display does not show SamePoints (Square Loyalty only)
Productization (n8n → SamePoints SaaS)
- Multi-tenant Postgres with
tenant_idon every row - Supabase auth, Shopify OAuth, Square OAuth per merchant
- Billing limits on synced orders per month
- Merchant dashboard: customers, ledger, manual gift card redeem, import CSV
From n8n workflows to SamePoints app
n8n was the right prototype tool: fast to wire webhooks, visible branches, easy experiments.
SamePoints is the product layer:
- One-click connect (no merchant webhook URLs)
- Refund-safe ledger UI
- Founder-readable docs and onboarding
- Same engine Pikapet runs daily — now for other AU omnichannel sellers
Pikapet remains our founding retail client; SamePoints is the software vendor.
FAQ
Can I still run this on n8n myself?
Yes — the pattern is valid. SamePoints packages what we operate for Pikapet: hosted Postgres, HMAC verification, reconcile, gift card issuance, and support for non-developers on the shop floor.
Why Postgres instead of Shopify metaobjects?
Metaobjects are great for merchandising. High-volume ledger rows, refund reversals, and Square+Shopify correlation fit a relational store better — then sync summaries outward.
Do customers redeem points in Square POS?
Redemption is on Shopify gift card (online checkout). Earn happens in both channels. Staff script: "Your points become a gift card on our website — same email at checkout."
What about Smile or Square Loyalty?
Use one earn engine. SamePoints = unified Shopify + Square payment ledger. Square Loyalty = separate Square-native program with Customer Display UI — do not stack both.
Next steps
- Omnichannel loyalty in Australia
- Shopify + Square points sync
- Try SamePoints — 14-day Starter trial via Shopify App Billing
Operator disclosure: SamePoints is operated from Australia. Pikapet is an independent client; this article describes architecture built for their requirements.
Related articles
- Gift card rewards vs discount codes for retention
Compare gift card rewards and discount codes for Shopify loyalty — which model improves repeat purchases, margin, and customer trust.
- Shopify + Square loyalty points without double counting
Learn how to run one shared loyalty balance across Shopify and Square while avoiding duplicate or missed rewards.
- Omnichannel loyalty for Australian Shopify and Square merchants
How Australian retailers unify Shopify online sales and Square in-store payments into one loyalty program customers actually trust.
Ready to unify Shopify and Square loyalty? Install the app, connect Square in Settings, and verify events in Logs.