Skip to content

Onboarding Flows

This folder contains structured onboarding flows for different POS/In-House Channel providers. Each onboarding document includes:

  1. Integration Type - Whether the integration is location-specific or merchant-scoped
  2. Prerequisites - Global required tasks that must be completed first
  3. Discovery Questions - Questions Emily asks to understand the merchant's needs
  4. Conditional Flows - Different setup paths based on answers
  5. Step-by-Step Instructions - Detailed steps with routes and actions

Integration Types

First-Party POS (Upvendo POS) — staged, test merchants only

Only test-flagged merchants can pick Upvendo POS on production. The upvendo provider is staged in the backend: config/pos-providers.php:51-52 sets 'active' => true, 'test_only' => true. The test_only flag is checked before the first_party bypass in both branches of ResellerService::getMerchantResellerProviders()ResellerService.php:675 (merchant with no reseller) and :731 (merchant under a reseller) — so in production GET /back-office/merchant/reseller-providers returns Upvendo POS only for merchants flagged is_test (test environments show it to everyone). Calling the endpoint by hand doesn't help a live merchant either: POST /back-office/pos/select-provider { provider: "upvendo" } passes request validation but is rejected with a 403 "Unsupported POS provider." by the test_only gate in FirstPartyPosProvisioningService::selectFirstPartyPos() (FirstPartyPosProvisioningService.php:70-77). No permission, role, country or reseller setting opens this for a live merchant — only dropping test_only in the backend config does (active stays the hard kill-switch).

The server side is real and end-to-end — selection endpoint, provisioning, registers, staff PINs — but it is a cash-only walking skeleton, not a finished product. routes/api/pos.php:8 heads the whole group "First-party POS (walking skeleton)"; settle accepts only amount_tendered, commented "Cash-only in the walking skeleton" (SettleOrderRequest.php:20-23), with no card tender anywhere under app/Http/Controllers/Api/Pos/; cash drawers are "Headless this wave: no UI" (routes/api/backoffice/pos.php:81-85). So while test merchants can now select it, what sits behind it would not yet run a card-taking venue. The linked Upvendo POS doc describes the flow: Upvendo's own point-of-sale, not a third-party integration. The config entry carries first_party: true (config/pos-providers.php:42), which bypasses the country and reseller-catalog filters, so it is offered in every country (to test merchants while test_only is set; to everyone once it is dropped). Selecting it marks the merchant first-party POS-connected directly — FirstPartyPosProvisioningService::selectFirstPartyPos() writes pos_provider = 'upvendo' on the merchant and mirrors it onto their locations — with no OAuth, no credentials, no "Connect …" step and no third-party integration record. The menu is built in Upvendo (source of truth) and published to the register/kiosk/online — no menu sync, no menu-abort. Setup = set up your Upvendo POS (add a device, create registers and staff PINs) + build & publish your menu.

  • Upvendo POS - First-party Upvendo register (staged test_only — test merchants only on production, see the gate above)

Location-Specific Integrations (Pull-Only Menu)

Each location must be connected separately. Requires creating a location first, then selecting it from the topbar before connecting.

Menu must exist in POS first - These integrations pull menu items from the POS. If the merchant doesn't have a menu in their POS, onboarding will abort.

  • Hendrickx - Belgian POS system
  • Vanhoutte - Belgian POS system (same as Hendrickx, uses Kassanet)
  • Shopcaisse - Shopcaisse POS (test_only — live merchants are not offered it on production; test-flagged merchants still are, see below)

Merchant-Scoped Integrations

Connects the entire merchant account in one step (not per location).

Catalog is synced from the POS — the POS is the source of truth for the menu/catalog (synced into Upvendo). This is not a two-way "create in either system" sync.

  • Square - Square POS (also processes payments, so a Payment Profile isn't needed); locations are imported from Square
  • MplusKassa - Dutch POS system (API ident + secret); locations imported from MplusKassa (branch names only)
  • Lightspeed K-Series - Lightspeed Restaurant K-Series POS (OAuth, no PKCE); locations are created in Upvendo and mapped to Lightspeed (test_only — live merchants are not offered it on production; test-flagged merchants still are, see below)

Which providers Emily actually offers

The POS-selection list comes from GET /back-office/merchant/reseller-providers (ResellerService::getMerchantResellerProviders()), and it filters on more than country:

  • active — an inactive provider is dropped first, ahead of every other rule (ResellerService.php:668, :726). This is the hard kill-switch: active => false hides a provider from everyone, test merchants included.
  • test_onlyShopcaisse, Lightspeed K-Series and the first-party Upvendo POS are marked test_only (config/pos-providers.php:130, :168, :52). On production GeneralHelper::isTestEnv() is false, so they are filtered out unless the merchant is itself flagged is_test — in both branches: merchant with no reseller (ResellerService.php:675) and merchant under a reseller (:731). Their backend endpoints are mostly not environment-gated, so a merchant who already has one keeps it and can still reach it — they simply are not offered as an onboarding choice. There is one server-side exception: Lightspeed's disconnect endpoint refuses on production. LightspeedKSeriesIntegrationController::disable() returns 400 "Disconnecting Lightspeed K-Series integration is disabled. Please contact administrator." whenever GeneralHelper::isTestEnv() is false (:55-59). The back office's Disconnect button is :disabled="!isTestEnv" with a matching tooltip (upvendo-backoffice/src/views/lightspeed/LightspeedForm.vue:246-253), so the greyed-out button mirrors a server refusal rather than being the only barrier — such a merchant can view and use the integration but cannot self-serve disconnect it by any route.
  • Reseller catalog — a merchant belonging to a reseller only sees the providers in that reseller's pos_providers list (ResellerService.php:739).
  • Country — a merchant with no reseller only sees providers whose countries list includes their country (ResellerService.php:686-688); the reseller branch does not apply a country filter at all.

Prerequisites

The connect-time prerequisite check is provider-specific, not universal. The backend's ThirdPartyIntegrationHelper::checkRequiredProfiles enforces a Branding profile at connect only for Hendrickx, Vanhoutte, Shopcaisse, and MplusKassa. Square runs the check but is not branding-gated. Lightspeed K-Series enforces no profile at connect — its OAuth path only checks that Upvendo's own Lightspeed client_id/client_secret are configured. Payment and Billing profiles are optional at connect for every provider and can be set up later.

A branding profile is still a genuine prerequisite for kiosk/storefront rendering on every provider — for Square and Lightspeed K-Series it simply isn't blocked at connect, so complete it before going live.

TaskRouteEnforced at connect?
Branding Profile/settings/brandYes — required for Hendrickx, Vanhoutte, Shopcaisse, MplusKassa. No for Square and Lightspeed K-Series (not branding-gated at connect, but still needed for kiosk/storefront rendering)
Payment Profile/settings/paymentsNo — optional (Square processes its own payments; Lightspeed needs a payment provider — Stripe/Viva — for online ordering, but it is not blocked at connect)
Billing Profile/settings/billingNo — optional

Also enforced: only one in-house POS per location/merchant — connecting a second is rejected ("Another in-house channel is already enabled"). This guard is keyed off the in-house channel lists in ThirdPartyIntegrationHelper.php:16-18, so it applies to the third-party in-house providers only. Upvendo POS is not in those lists and creates no ThirdPartyIntegration at all, so selecting it never trips this check (:137-139).


How Onboarding Works

For Location-Specific Integrations (Hendrickx, Vanhoutte, Shopcaisse)

  1. Emily checks if global prerequisites are complete
  2. Emily guides merchant to complete any missing prerequisites
  3. Emily asks merchant to create a location
  4. Emily reminds merchant to select the location from the topbar
  5. Emily asks discovery questions (channels, menu status)
  6. If menu not in POS → Onboarding aborts with message to create menu in POS first
  7. Emily guides through integration connection
  8. Emily confirms when setup is complete

For Merchant-Scoped Integrations (Square, MplusKassa, Lightspeed K-Series)

  1. Emily checks if global prerequisites are complete
  2. Emily guides merchant to complete any missing prerequisites
  3. Emily asks discovery questions (channels, menu status)
  4. Emily guides through integration connection (OAuth for Square and Lightspeed K-Series, API credentials for MplusKassa)
  5. Square and MplusKassa: Locations are imported automatically from the POS Lightspeed K-Series: Locations must be created manually in Upvendo
  6. Emily reminds merchant to complete missing location fields (address, coordinates, etc.)
  7. Emily confirms when setup is complete

Key Differences Summary

IntegrationScopePayment ProfileLocation CreationMenu Sync
HendrickxLocation-specificOptionalManualPull-only (POS owns catalog; must exist in POS)
VanhoutteLocation-specificOptionalManualPull-only (POS owns catalog; must exist in POS)
ShopcaisseLocation-specificOptionalAuto-created per Shopcaisse store on connectPull-only (POS owns catalog)
SquareMerchant-scopedNot needed (Square processes payments)Auto-imported from SquareSynced from Square
MplusKassaMerchant-scopedOptionalAuto-imported (branch names only — merchant completes details)Pull-only (POS owns catalog)
Lightspeed K-SeriesMerchant-scopedOptional at connect (needs Stripe/Viva for payments)Manual — create in Upvendo, then map to LightspeedStructure pulled from Lightspeed; Upvendo-created items push back (categories pull-only)