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 business 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 connect 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. The business profile is not checked at connect for any provider and can be set up later — but it is required before accepting customer payments. One business profile covers payments (Stripe / Viva Wallet) and Upvendo's billing (its Billing tab).
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) |
Business profile ("Set up Business Profile" step; billing is its Billing tab — /settings/billing forwards there) | /settings/payments (Settings → Business profile) | No — but required before accepting customer payments (Square processes its own payments; Lightspeed needs a payment provider — Stripe/Viva — for online ordering, but it is not blocked at connect) |
Linking a location: Settings → Locations → edit the location → section Business Profile ("Which business profile this location belongs to") → one Business Profile selector. Billing is derived from that business profile and shown read-only ("Billed through billing profile …"); a Billing Profile picker appears only when the business profile has more than one billing profile, and "No billing profile yet" links (Set up billing) to that business profile's Billing tab. Square merchants have no business-profile selector and keep a plain Billing Profile picker.
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 | Business 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) |