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)

Diagram of webhooks flowing through Postgres and metafields to Shopify gift card redemption

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.

  1. Parse eligible line items (skip gift-card-only payments where configured)
  2. auditable_amount × points_per_dollar → integer points
  3. Upsert customer (email / phone / Shopify customer id)
  4. Insert ledger row with order_reference for idempotency
  5. Update balance → push metafield

Square

Listen to payment.updated (completed) and refund events — not Square Loyalty API.

  1. Resolve customer by phone, email, or prior link
  2. amount_aud × points_per_dollar
  3. 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_id on 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


Operator disclosure: SamePoints is operated from Australia. Pikapet is an independent client; this article describes architecture built for their requirements.

Related articles

Ready to unify Shopify and Square loyalty? Install the app, connect Square in Settings, and verify events in Logs.