Skip to content

Square Integration Setup

Looking for guided setup? Start Emily in the backoffice for step-by-step guided setup.

Overview

Square is a merchant-scoped full POS integration that handles both order management and payment processing. Unlike other integrations, Square manages payments directly -- no separate payment provider is needed. Menu items, orders, locations, and inventory sync bidirectionally.

Integration Type: Full POS integration (merchant-scoped, not location-scoped) Sync Direction: Bidirectional for locations, menu (categories, items, modifier groups, variant groups), and inventory Payment Handling: Square handles all payments -- kiosk (Square Terminal) and online (Square Web Payments SDK) Authentication: OAuth2 authorization code flow with PKCE-style state parameter

Menu Flexibility: You can either sync your existing menu from Square OR create items in Upvendo and push them to Square.

Key Benefits:

  • No Payment Profile needed -- Square handles kiosk payments (Square Terminal) and online payments (Square Web Payments SDK)
  • Locations are imported automatically with rich data (address, business hours, coordinates, timezone, currency, social links)
  • Bidirectional sync for menu items, categories, modifiers, variant groups, and inventory
  • Real-time webhooks for location changes, catalog updates, inventory changes, device pairing, and payment confirmations

Purpose

The Square integration serves merchants who use Square as their POS system and want to:

  • Use Upvendo's kiosk and online ordering channels powered by Square payments
  • Keep their menu, locations, and inventory synchronized between Square and Upvendo
  • Process payments through Square Terminal (kiosk) or Square Web Payments SDK (online)
  • Manage everything from a single back-office while keeping Square as the source of truth for payments

Key Concepts

ConceptDescription
Merchant-ScopedUnlike Deliveroo/Uber Eats (location-scoped), the Square integration covers the entire merchant account. All locations under the Square merchant are synced.
SquareIntegration RecordA specialized integration record (extends ThirdPartyIntegration) storing OAuth tokens, merchant ID, sync status, logs, and settings. Provider is square.
External IDsUpvendo entities (locations, items, categories, modifier groups) store their Square counterpart IDs in external_ids.square or external_data.square.
Sync DirectionFor each entity, the system determines whether to push (Upvendo to Square), pull (Square to Upvendo), or skip based on timestamps and hash comparison.
Sync HashAn MD5 hash of the Square entity's JSON representation, stored on the Upvendo entity to detect changes in Square.
Last Synced AtTimestamp of when Upvendo last pushed data TO Square. Used with the sync hash to determine sync direction.
Daily Auto-SyncA configurable daily sync that runs locations, menus, and inventory sync on a schedule.
Terminal CheckoutThe flow for processing kiosk payments through a paired Square Terminal device.

Prerequisites

Square integration is simpler than other POS systems because it handles payments:

1. Branding Profile Setup (Required)

  1. Go to Settings -> Brand (/settings/brand)
  2. Configure your store's branding (logo, colors, fonts)
  3. Square imports social links (Facebook, X, Instagram) automatically, but does NOT provide colors, fonts, or logos

2. Billing Profile Setup (Optional)

  1. Go to Settings -> Billing (/settings/billing)
  2. Complete your billing information for Upvendo platform invoicing
  3. This is for Upvendo billing only -- NOT related to customer payments (Square handles those)

Note: Payment Profile is NOT required -- Square handles all customer payments directly.


Setup Steps

1. Connect Square Account (OAuth)

  1. Go to Square (/square)
  2. Click Connect with Square
  3. You are redirected to Square's OAuth authorization page
  4. Log in to your Square account
  5. Authorize Upvendo to access your Square data
  6. After authorization, a full sync starts automatically (locations, menu, inventory)

OAuth Technical Details:

The OAuth flow requests these scopes:

  • MERCHANT_PROFILE_READ, MERCHANT_PROFILE_WRITE -- Merchant and location info
  • ITEMS_READ, ITEMS_WRITE -- Catalog management (items, categories, modifiers, pricing)
  • ORDERS_READ, ORDERS_WRITE -- Order management
  • PAYMENTS_READ, PAYMENTS_WRITE -- Payment processing
  • INVENTORY_READ, INVENTORY_WRITE -- Stock level management
  • CUSTOMERS_READ, CUSTOMERS_WRITE -- Customer info for orders/payments
  • DEVICES_READ, DEVICE_CREDENTIAL_MANAGEMENT -- Terminal device management

The state parameter contains a JSON-encoded, base64-encoded payload with vendor_id, timestamp, and a random nonce for CSRF protection.

Token exchange:

  • Authorization code is exchanged at POST https://connect.squareup.com/oauth2/token (or sandbox equivalent)
  • Response includes: access_token, refresh_token, expires_at, refresh_token_expires_at, merchant_id
  • All token data is stored in the SquareIntegration record
  • The vendor's provider_integrated is set to square

2. Locations Imported Automatically

Once connected, Upvendo automatically:

  • Imports all Square locations with address, business hours, coordinates, timezone, currency, language, phone, and email
  • Creates a branding profile per location (with defaults + social links from Square)
  • Links billing using the default billing profile's Stripe customer ID (if exists)

After import, go to Settings -> Locations (/settings/locations) to:

  • Verify imported data is correct
  • Customize branding (logo, colors, fonts -- Square doesn't provide these)
  • Add delivery zones (if doing delivery)

3. Configure Sync Settings

SettingDescription
Daily Sync TimeTime of day when automatic sync runs (menu, locations, inventory). Format: HH:00 or HH:30.

The only configurable setting is the daily sync time. All sync features (menu, locations, inventory) run automatically. You can also trigger a manual sync at any time from the Status tab.

4. Test the Integration

  1. Go to the Square page -> Status tab
  2. Click Test Connection to verify API connectivity (fetches merchant info from Square)
  3. Click Sync Now to run a manual sync
  4. For kiosk: pair a Square Terminal and process a test payment
  5. For online ordering: place a test order and verify payment completes

Data Sync Details

Bidirectional Sync Direction Algorithm

For every entity (location, category, item, modifier group), the system determines sync direction using this algorithm:

  1. Get last_synced_at -- when Upvendo last pushed TO Square
  2. Get last_sync_hash -- MD5 hash of Square entity at last sync
  3. Compare Upvendo updated_at against last_synced_at to detect Upvendo changes
  4. Compare current Square hash against last_sync_hash to detect Square changes
Upvendo ChangedSquare ChangedWebhook ContextResult
NoNoAnySkip (no sync needed)
YesNoAnyPush Upvendo to Square
NoYesAnyPull Square to Upvendo
YesYesYes (webhook)Square wins (webhook just fired, so Square changed most recently)
YesYesNo (manual)Most recent wins (compare updated_at vs last_synced_at)

First sync (no last_synced_at): Defaults to pushing from Upvendo to Square.

Location Sync

Phase 1: Sync Upvendo locations to Square

  • For each Upvendo location, determine sync direction
  • Push to Square: create or update the Square location with name, address, timezone, business hours, phone, email, website, description, status, coordinates, social links
  • Pull from Square: update the Upvendo location with Square data

Phase 2: Import unsynced Square locations

  • Any Square locations not already linked to an Upvendo location are imported
  • New Upvendo locations are created with branding profiles

Data mapped:

Square FieldUpvendo Field
namename (unique name generation if conflict)
addressaddress (via SquareAddressConverter)
timezonetimezone
business_hoursbusiness_hours (via SquareBusinessHoursConverter)
phone_numbercontact_information.phone
business_emailcontact_information.email
language_codepreferred_language
coordinatespin_point_latitude, pin_point_longitude
facebook_urlbranding_profile.social_links.facebook
twitter_usernamebranding_profile.social_links.x
instagram_usernamebranding_profile.social_links.instagram
website_urlonline_ordering_url
descriptiondescription
statusstatus
currencycurrency

Menu sync is fully bidirectional. It syncs three entity types in order:

  1. Categories -- bidirectional sync between Upvendo categories and Square catalog categories
  2. Modifier Groups -- bidirectional sync between Upvendo modifier groups and Square modifier lists
  3. Items -- bidirectional sync between Upvendo items and Square catalog items (including variant groups)

Incremental sync: When triggered by a specific entity change (via SyncSquareMenuJob), only the changed entity is synced:

  • category -> syncSingleCategory()
  • modifier_group -> syncSingleModifierGroup()
  • item -> syncSingleItem()
  • variant_group -> syncSingleVariantGroup()

Full sync: When triggered by a webhook (catalog.version.updated) or daily auto-sync, all categories, modifier groups, and items are synced.

SyncSquareMenuJob configuration:

  • Max retries: 3
  • Backoff: 60 seconds between retries

Inventory Sync

Inventory sync is bidirectional, per item variation per location:

Push (Upvendo to Square): Sends stock level changes to Square via the Inventory API. Pull (Square to Upvendo): Reads stock levels from Square and updates Upvendo.

Inventory sync runs as part of the full sync (daily auto-sync or manual sync). Webhook-triggered inventory syncs (SyncSquareInventoryJob) target specific catalog objects and locations.

Propagation Across Locations

When a modifier group is updated in Upvendo and pushed to Square, the system propagates the Upvendo data to all other locations that share the same Square modifier list ID. This ensures consistency across multi-location setups.


Webhook Events

Square sends webhooks to POST /webhook/square, verified by the verify.square-webhook middleware. The SquareWebhookService routes events by type.

Event Deduplication

Square may retry failed webhooks. The system deduplicates by caching processed event_id values for 24 hours.

Anti-Recursion Protection

When Upvendo pushes changes to Square, a cache timestamp is set. If a webhook arrives within 10 seconds (15 seconds for inventory) of a push, it is skipped to prevent recursive update loops.

Event Types

Event PrefixHandlerJobs Dispatched
location.createdhandleLocationEvent()SyncSquareLocationJob
location.updatedhandleLocationEvent()SyncSquareLocationJob
catalog.version.updatedhandleCatalogEvent()SyncSquareMenuJob (full sync)
inventory.count.updatedhandleInventoryEvent()SyncSquareInventoryJob
device.code.pairedhandleDeviceCodeEvent()None (direct update)
payment.updatedhandlePaymentEvent()None (direct processing)

Device Code Pairing (device.code.paired)

When a Square Terminal is paired:

  1. The webhook contains the device_code_id, device_id, code, and location_id
  2. The system finds the Upvendo device with a pending device code matching the device_code_id
  3. Updates the device record: sets terminal_device_id, marks as connected, clears pending flag, records paired timestamp

Payment Processing (payment.updated)

When a payment completes:

  1. Only payment.updated with status COMPLETED is processed
  2. The reference_id (Upvendo order_no) identifies the transaction
  3. The location_id maps to an Upvendo location via external ID
  4. Online ordering payments: Triggers OnlineOrderingOrchestrator::verifyPayment() with a database lock
  5. Kiosk payments: Triggers PaymentCaptureService::capturePayment() with a database lock
  6. Both use 30-second locks to prevent duplicate processing

Actions

ActionMethodEndpointDescription
Get StatusGET/square/statusReturns integration status, sync info, settings
Initiate OAuthPOST/square/oauthGenerates Square OAuth authorization URL
Update Sync TimePOST/square/sync-timeSet the daily auto-sync time (format: HH:00 or HH:30)
DisablePOST/square/disableDisable the Square integration
Start SyncPOST/square/start-syncTrigger a manual full sync (dispatches SyncSquareIntegrationJob)
Test ConnectionGET/square/testTest API connectivity by fetching merchant info
OAuth CallbackGET/square-callbackHandles OAuth redirect from Square (guest route)

Fields

Status Response

FieldTypeDescription
is_connectedbooleanWhether the integration is active
providerstringAlways square
vendor_idstringThe vendor this integration belongs to
is_sandboxbooleanWhether using sandbox environment
merchant_idstringSquare merchant ID
access_token_expires_atstringWhen the access token expires
is_token_expiredbooleanWhether the token needs refresh
settingsobjectIntegration settings (sync_time, etc.)
sync_statusobjectCurrent sync status, logs, connection status
last_sync_atstringTimestamp of last successful sync
sync_timestringConfigured daily auto-sync time

Sync Time Request

FieldTypeRequiredValidation
sync_timestringYesMust match HH:00 or HH:30 format (regex: `^([01]?[0-9]

Payment Flow

Kiosk Payments (Square Terminal)

Customer Order -> Upvendo Kiosk -> Create Square Order -> Create Terminal Checkout -> Payment on Terminal -> payment.updated Webhook -> PaymentCaptureService

Terminal Checkout Details:

  1. A Square Order is created first (if not already existing) with line items from the transaction
  2. A Terminal Checkout is created linking the order to the paired device
  3. Configuration: skip receipt screen = false, collect signature = false, allow tipping = false
  4. The checkout amount is the transaction total in smallest currency unit (cents)
  5. The referenceId links back to the Upvendo order_no
  6. The checkout ID and status are stored on the transaction's external data
  7. Payment confirmation arrives via the payment.updated webhook

Terminal Checkout Statuses:

  • PENDING -- Checkout created, waiting for terminal
  • IN_PROGRESS -- Customer interacting with terminal
  • CANCEL_REQUESTED -- Cancellation requested
  • CANCELED -- Checkout cancelled
  • COMPLETED -- Payment successful

Cancellation: Terminal checkouts can be cancelled via cancelTerminalCheckout().

Online Ordering Payments (Square Web Payments SDK)

Customer Order -> Online Ordering -> Square Web Payments SDK (card tokenization) -> Square Payments API -> payment.updated Webhook -> OnlineOrderingOrchestrator::verifyPayment()

Square Web Payments SDK replaces Stripe for online payments. No Stripe or Viva Wallet configuration needed.

When Square is connected, it automatically handles all payments -- the system routes to Square based on the merchant's integration status.


Business Rules

  1. Merchant-scoped, not location-scoped: One Square integration covers all locations under the merchant. All locations sync together.
  2. Provider exclusivity: When Square is connected, the vendor's provider_integrated is set to square. This disables other payment providers.
  3. Token management: Access tokens have an expiration. The system stores expires_at and refresh_token_expires_at for token lifecycle management.
  4. Sandbox vs Production: Determined by config('square.sandbox'). Sandbox uses connect.squareupsandbox.com and Environments::Sandbox. Production uses connect.squareup.com and Environments::Production.
  5. Sync is non-destructive: The sync direction algorithm prevents overwriting newer changes. Conflicts are resolved based on timestamps and webhook context.
  6. Webhook deduplication: Event IDs are cached for 24 hours to prevent duplicate processing.
  7. Anti-recursion: Cache-based timestamps prevent webhook processing within 10-15 seconds of a push to Square.
  8. Sync logs: The integration keeps the last 100 log entries. Duplicate consecutive logs update the timestamp instead of creating new entries.
  9. Full sync order: Test connection -> Locations -> Menus -> Inventory -> Update sync status.
  10. SyncSquareIntegrationJob: Runs with 3 retries, 10-minute timeout, and runs after database commit (afterCommit).

Square-Specific Features

Terminal Integration

  1. Go to Device Management -> Devices (/device-management/devices)
  2. Select a device and open the Square Terminal section
  3. Click Generate Device Code -- a pairing code is created
  4. Enter the code on the Square Terminal within 5 minutes
  5. Once paired, a webhook (device.code.paired) confirms the connection and the terminal is ready

Catalog Sync (Bidirectional)

  • Items, categories, modifier groups, variant groups sync both ways
  • Changes in Upvendo push to Square automatically (via SyncSquareMenuJob or daily sync)
  • Changes in Square pull to Upvendo automatically (via catalog webhooks)
  • Conflict resolution: uses timestamp + hash comparison; webhook-triggered changes from Square win in conflict

Inventory Sync

  • Stock levels sync bidirectionally between Upvendo and Square
  • Changes are tracked per item variation per location
  • Webhook-triggered for real-time updates (SyncSquareInventoryJob)

Daily Auto-Sync

  • Configurable sync time in the Square page -> Settings tab
  • Runs a full sync: connection test -> locations -> menus -> inventory
  • Managed by the InHouseAutoSyncCommand scheduler

FAQs

Do I need to set up a payment profile for Square?

No. Square handles all payments directly. You do not need to configure Stripe, Viva Wallet, or any other payment provider when Square is connected.

What happens when I connect Square for the first time?

After OAuth authorization, a full sync runs automatically: all Square locations are imported with their data, the menu catalog is synced, and inventory levels are pulled. This may take a few minutes depending on the size of your catalog.

Can I create items in Upvendo and push them to Square?

Yes. The sync is bidirectional. Items created in Upvendo will be pushed to Square on the next sync (manual or daily). Items created in Square will be pulled to Upvendo.

How does conflict resolution work?

When both Upvendo and Square have changed the same entity since the last sync: in webhook context (Square just changed), Square wins. In manual sync context, the most recently modified side wins based on timestamps.

What data does Square NOT provide?

Square does not provide branding data like logos, colors, or fonts. You must configure these manually in the Upvendo Branding Profile after locations are imported.

Can I use Square for only kiosk OR only online ordering?

Yes. Square handles both, but you can configure which channels are active per location. The payment routing automatically adapts based on the order channel.

How often does the daily sync run?

At the time you configure in the Settings tab. The sync time must be in HH:00 or HH:30 format. The sync runs once per day at the specified time.

What happens if I disconnect Square?

Disconnecting sets the integration to inactive and clears the vendor's provider_integrated field. This means no more payment processing until an alternative (Stripe, Viva Wallet) is configured. Menu sync also stops.


Troubleshooting

"OAuth connection failed"

  • Verify the Square account is active and in good standing
  • Ensure you have owner or admin permissions on the Square account
  • Try disconnecting and reconnecting from the Square page (/square)
  • Check that the Square Application ID and Secret are correctly configured in the backend
  • For sandbox: ensure you have a sandbox seller dashboard open in another browser tab

"Locations not appearing after connecting"

  • The first sync runs automatically -- check the sync status on the Square page -> Status tab
  • If sync shows "in progress" for too long, check the logs for errors
  • Click Sync Now to trigger a manual sync
  • The SyncSquareIntegrationJob has a 10-minute timeout -- check if it timed out
  • Trigger manual sync: Square page -> Status tab -> Sync Now
  • Menu sync is bidirectional -- items created in either system will sync
  • Check the daily sync time is configured in the Settings tab
  • Review sync logs for specific item errors
  • For single-entity sync issues, check the SyncSquareMenuJob logs (retries 3 times with 60-second backoff)

"Payments not processing"

  • Verify the location is synced with Square (location should have a Square external ID)
  • Check the Square Dashboard for account holds or verification requirements
  • For kiosk: ensure the Square Terminal is paired and online
  • For online: verify the Square application ID is correctly configured
  • Check the payment.updated webhook is being received and processed

"Square Terminal not connecting"

  • Ensure the terminal is powered on and connected to the internet
  • Generate a new device code (codes expire after 5 minutes)
  • The terminal must be signed into the same Square account connected to Upvendo
  • Check the device webhook status -- pairing is confirmed via device.code.paired webhook
  • Verify the device record shows is_pending: true before pairing

"Inventory counts are wrong"

  • Trigger a manual sync to pull latest counts from Square
  • Check that the item variation has a Square external ID (unsynced items won't have inventory)
  • Verify the correct Square location is mapped to the Upvendo location
  • Check the anti-recursion cache -- inventory webhook has a 15-second cooldown after pushes

"Sync seems stuck or running too long"

  • The SyncSquareIntegrationJob has a 10-minute timeout
  • Check sync logs on the Status tab for errors
  • If the job failed, it retries up to 3 times
  • Click Sync Now to start a fresh sync
  • Check the queue worker is running and processing jobs

"Changes in Square are not reflected in Upvendo"

  • Verify the verify.square-webhook middleware is not rejecting Square webhooks
  • Check that the webhook URL POST /webhook/square is registered in the Square Developer Dashboard
  • The anti-recursion cache may be blocking the webhook (10-second cooldown for catalog/locations, 15 for inventory)
  • Trigger a manual sync to force-pull from Square

Disconnecting Square

If you need to disconnect Square:

  1. Go to Square (/square) -> Settings tab
  2. Click Delete and confirm
  3. This disables the integration and removes Square as the payment provider

Warning: Disconnecting Square means:

  • No more payment processing (kiosk and online) until an alternative is configured
  • Menu sync stops
  • Set up Stripe (online) and/or Viva Wallet (kiosk) as alternatives before disconnecting

Assistant Guidance

When helping users with Square integration:

  • Square is merchant-scoped -- one connection covers all locations. Do not suggest per-location setup.
  • The first sync after OAuth runs automatically. If locations or items are missing, suggest a manual Sync Now.
  • For payment issues, check that the location has a Square external ID and the terminal (if kiosk) is paired.
  • Square handles all payments -- do not suggest configuring Stripe or Viva Wallet when Square is active.
  • Conflict resolution favors Square in webhook context and most-recent-change in manual sync.
  • Branding (logos, colors, fonts) must be set manually -- Square does not provide these.

Relations