Appearance
Onboarding Flows
This folder contains structured onboarding flows for different POS/In-House Channel providers. Each onboarding document includes:
- Integration Type - Whether the integration is location-specific or merchant-scoped
- Prerequisites - Global required tasks that must be completed first
- Discovery Questions - Questions Emily asks to understand the merchant's needs
- Conditional Flows - Different setup paths based on answers
- 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
upvendoprovider is staged in the backend:config/pos-providers.php:51-52sets'active' => true, 'test_only' => true. Thetest_onlyflag is checked before thefirst_partybypass in both branches ofResellerService::getMerchantResellerProviders()—ResellerService.php:675(merchant with no reseller) and:731(merchant under a reseller) — so in productionGET /back-office/merchant/reseller-providersreturns Upvendo POS only for merchants flaggedis_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 thetest_onlygate inFirstPartyPosProvisioningService::selectFirstPartyPos()(FirstPartyPosProvisioningService.php:70-77). No permission, role, country or reseller setting opens this for a live merchant — only droppingtest_onlyin the backend config does (activestays 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 => falsehides a provider from everyone, test merchants included.test_only— Shopcaisse, Lightspeed K-Series and the first-party Upvendo POS are markedtest_only(config/pos-providers.php:130,:168,:52). On productionGeneralHelper::isTestEnv()is false, so they are filtered out unless the merchant is itself flaggedis_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." wheneverGeneralHelper::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_providerslist (ResellerService.php:739). - Country — a merchant with no reseller only sees providers whose
countrieslist 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.
| Task | Route | Enforced at connect? |
|---|---|---|
| Branding Profile | /settings/brand | Yes — 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/payments | No — 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/billing | No — 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)
- Emily checks if global prerequisites are complete
- Emily guides merchant to complete any missing prerequisites
- Emily asks merchant to create a location
- Emily reminds merchant to select the location from the topbar
- Emily asks discovery questions (channels, menu status)
- If menu not in POS → Onboarding aborts with message to create menu in POS first
- Emily guides through integration connection
- Emily confirms when setup is complete
For Merchant-Scoped Integrations (Square, MplusKassa, Lightspeed K-Series)
- Emily checks if global prerequisites are complete
- Emily guides merchant to complete any missing prerequisites
- Emily asks discovery questions (channels, menu status)
- Emily guides through integration connection (OAuth for Square and Lightspeed K-Series, API credentials for MplusKassa)
- Square and MplusKassa: Locations are imported automatically from the POS Lightspeed K-Series: Locations must be created manually in Upvendo
- Emily reminds merchant to complete missing location fields (address, coordinates, etc.)
- Emily confirms when setup is complete
Key Differences Summary
| Integration | Scope | Payment Profile | Location Creation | Menu Sync |
|---|---|---|---|---|
| Hendrickx | Location-specific | Optional | Manual | Pull-only (POS owns catalog; must exist in POS) |
| Vanhoutte | Location-specific | Optional | Manual | Pull-only (POS owns catalog; must exist in POS) |
| Shopcaisse | Location-specific | Optional | Auto-created per Shopcaisse store on connect | Pull-only (POS owns catalog) |
| Square | Merchant-scoped | Not needed (Square processes payments) | Auto-imported from Square | Synced from Square |
| MplusKassa | Merchant-scoped | Optional | Auto-imported (branch names only — merchant completes details) | Pull-only (POS owns catalog) |
| Lightspeed K-Series | Merchant-scoped | Optional at connect (needs Stripe/Viva for payments) | Manual — create in Upvendo, then map to Lightspeed | Structure pulled from Lightspeed; Upvendo-created items push back (categories pull-only) |