Appearance
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
| Concept | Description |
|---|---|
| Merchant-Scoped | Unlike Deliveroo/Uber Eats (location-scoped), the Square integration covers the entire merchant account. All locations under the Square merchant are synced. |
| SquareIntegration Record | A specialized integration record (extends ThirdPartyIntegration) storing OAuth tokens, merchant ID, sync status, logs, and settings. Provider is square. |
| External IDs | Upvendo entities (locations, items, categories, modifier groups) store their Square counterpart IDs in external_ids.square or external_data.square. |
| Sync Direction | For each entity, the system determines whether to push (Upvendo to Square), pull (Square to Upvendo), or skip based on timestamps and hash comparison. |
| Sync Hash | An MD5 hash of the Square entity's JSON representation, stored on the Upvendo entity to detect changes in Square. |
| Last Synced At | Timestamp of when Upvendo last pushed data TO Square. Used with the sync hash to determine sync direction. |
| Daily Auto-Sync | A configurable daily sync that runs locations, menus, and inventory sync on a schedule. |
| Terminal Checkout | The 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)
- Go to Settings -> Brand (
/settings/brand) - Configure your store's branding (logo, colors, fonts)
- Square imports social links (Facebook, X, Instagram) automatically, but does NOT provide colors, fonts, or logos
2. Billing Profile Setup (Optional)
- Go to Settings -> Billing (
/settings/billing) - Complete your billing information for Upvendo platform invoicing
- 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)
- Go to Square (
/square) - Click Connect with Square
- You are redirected to Square's OAuth authorization page
- Log in to your Square account
- Authorize Upvendo to access your Square data
- 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 infoITEMS_READ,ITEMS_WRITE-- Catalog management (items, categories, modifiers, pricing)ORDERS_READ,ORDERS_WRITE-- Order managementPAYMENTS_READ,PAYMENTS_WRITE-- Payment processingINVENTORY_READ,INVENTORY_WRITE-- Stock level managementCUSTOMERS_READ,CUSTOMERS_WRITE-- Customer info for orders/paymentsDEVICES_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_integratedis set tosquare
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
| Setting | Description |
|---|---|
| Daily Sync Time | Time 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
- Go to the Square page -> Status tab
- Click Test Connection to verify API connectivity (fetches merchant info from Square)
- Click Sync Now to run a manual sync
- For kiosk: pair a Square Terminal and process a test payment
- 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:
- Get
last_synced_at-- when Upvendo last pushed TO Square - Get
last_sync_hash-- MD5 hash of Square entity at last sync - Compare Upvendo
updated_atagainstlast_synced_atto detect Upvendo changes - Compare current Square hash against
last_sync_hashto detect Square changes
| Upvendo Changed | Square Changed | Webhook Context | Result |
|---|---|---|---|
| No | No | Any | Skip (no sync needed) |
| Yes | No | Any | Push Upvendo to Square |
| No | Yes | Any | Pull Square to Upvendo |
| Yes | Yes | Yes (webhook) | Square wins (webhook just fired, so Square changed most recently) |
| Yes | Yes | No (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 Field | Upvendo Field |
|---|---|
| name | name (unique name generation if conflict) |
| address | address (via SquareAddressConverter) |
| timezone | timezone |
| business_hours | business_hours (via SquareBusinessHoursConverter) |
| phone_number | contact_information.phone |
| business_email | contact_information.email |
| language_code | preferred_language |
| coordinates | pin_point_latitude, pin_point_longitude |
| facebook_url | branding_profile.social_links.facebook |
| twitter_username | branding_profile.social_links.x |
| instagram_username | branding_profile.social_links.instagram |
| website_url | online_ordering_url |
| description | description |
| status | status |
| currency | currency |
Menu Sync (Categories, Modifier Groups, Items)
Menu sync is fully bidirectional. It syncs three entity types in order:
- Categories -- bidirectional sync between Upvendo categories and Square catalog categories
- Modifier Groups -- bidirectional sync between Upvendo modifier groups and Square modifier lists
- 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 Prefix | Handler | Jobs Dispatched |
|---|---|---|
location.created | handleLocationEvent() | SyncSquareLocationJob |
location.updated | handleLocationEvent() | SyncSquareLocationJob |
catalog.version.updated | handleCatalogEvent() | SyncSquareMenuJob (full sync) |
inventory.count.updated | handleInventoryEvent() | SyncSquareInventoryJob |
device.code.paired | handleDeviceCodeEvent() | None (direct update) |
payment.updated | handlePaymentEvent() | None (direct processing) |
Device Code Pairing (device.code.paired)
When a Square Terminal is paired:
- The webhook contains the
device_code_id,device_id,code, andlocation_id - The system finds the Upvendo device with a pending device code matching the
device_code_id - 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:
- Only
payment.updatedwith statusCOMPLETEDis processed - The
reference_id(Upvendo order_no) identifies the transaction - The
location_idmaps to an Upvendo location via external ID - Online ordering payments: Triggers
OnlineOrderingOrchestrator::verifyPayment()with a database lock - Kiosk payments: Triggers
PaymentCaptureService::capturePayment()with a database lock - Both use 30-second locks to prevent duplicate processing
Actions
| Action | Method | Endpoint | Description |
|---|---|---|---|
| Get Status | GET | /square/status | Returns integration status, sync info, settings |
| Initiate OAuth | POST | /square/oauth | Generates Square OAuth authorization URL |
| Update Sync Time | POST | /square/sync-time | Set the daily auto-sync time (format: HH:00 or HH:30) |
| Disable | POST | /square/disable | Disable the Square integration |
| Start Sync | POST | /square/start-sync | Trigger a manual full sync (dispatches SyncSquareIntegrationJob) |
| Test Connection | GET | /square/test | Test API connectivity by fetching merchant info |
| OAuth Callback | GET | /square-callback | Handles OAuth redirect from Square (guest route) |
Fields
Status Response
| Field | Type | Description |
|---|---|---|
is_connected | boolean | Whether the integration is active |
provider | string | Always square |
vendor_id | string | The vendor this integration belongs to |
is_sandbox | boolean | Whether using sandbox environment |
merchant_id | string | Square merchant ID |
access_token_expires_at | string | When the access token expires |
is_token_expired | boolean | Whether the token needs refresh |
settings | object | Integration settings (sync_time, etc.) |
sync_status | object | Current sync status, logs, connection status |
last_sync_at | string | Timestamp of last successful sync |
sync_time | string | Configured daily auto-sync time |
Sync Time Request
| Field | Type | Required | Validation |
|---|---|---|---|
sync_time | string | Yes | Must 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 -> PaymentCaptureServiceTerminal Checkout Details:
- A Square Order is created first (if not already existing) with line items from the transaction
- A Terminal Checkout is created linking the order to the paired device
- Configuration: skip receipt screen = false, collect signature = false, allow tipping = false
- The checkout amount is the transaction total in smallest currency unit (cents)
- The
referenceIdlinks back to the Upvendo order_no - The checkout ID and status are stored on the transaction's external data
- Payment confirmation arrives via the
payment.updatedwebhook
Terminal Checkout Statuses:
PENDING-- Checkout created, waiting for terminalIN_PROGRESS-- Customer interacting with terminalCANCEL_REQUESTED-- Cancellation requestedCANCELED-- Checkout cancelledCOMPLETED-- 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
- Merchant-scoped, not location-scoped: One Square integration covers all locations under the merchant. All locations sync together.
- Provider exclusivity: When Square is connected, the vendor's
provider_integratedis set tosquare. This disables other payment providers. - Token management: Access tokens have an expiration. The system stores
expires_atandrefresh_token_expires_atfor token lifecycle management. - Sandbox vs Production: Determined by
config('square.sandbox'). Sandbox usesconnect.squareupsandbox.comandEnvironments::Sandbox. Production usesconnect.squareup.comandEnvironments::Production. - Sync is non-destructive: The sync direction algorithm prevents overwriting newer changes. Conflicts are resolved based on timestamps and webhook context.
- Webhook deduplication: Event IDs are cached for 24 hours to prevent duplicate processing.
- Anti-recursion: Cache-based timestamps prevent webhook processing within 10-15 seconds of a push to Square.
- Sync logs: The integration keeps the last 100 log entries. Duplicate consecutive logs update the timestamp instead of creating new entries.
- Full sync order: Test connection -> Locations -> Menus -> Inventory -> Update sync status.
- SyncSquareIntegrationJob: Runs with 3 retries, 10-minute timeout, and runs after database commit (
afterCommit).
Square-Specific Features
Terminal Integration
- Go to Device Management -> Devices (
/device-management/devices) - Select a device and open the Square Terminal section
- Click Generate Device Code -- a pairing code is created
- Enter the code on the Square Terminal within 5 minutes
- 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
InHouseAutoSyncCommandscheduler
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
SyncSquareIntegrationJobhas a 10-minute timeout -- check if it timed out
"Menu items not syncing"
- 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
SyncSquareMenuJoblogs (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.updatedwebhook 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.pairedwebhook - Verify the device record shows
is_pending: truebefore 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
SyncSquareIntegrationJobhas 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-webhookmiddleware is not rejecting Square webhooks - Check that the webhook URL
POST /webhook/squareis 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:
- Go to Square (
/square) -> Settings tab - Click Delete and confirm
- 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.