Skip to content

Hendrickx Onboarding (Reseller)

Overview

How a reseller (partner) brings a merchant onto Upvendo with the Hendrickx in-house POS. Hendrickx is part of the Kassanet family (shared with Vanhoutte) and is a location-specific integration: each location connects its own Hendrickx register with its own credentials.

Two distinct surfaces are involved:

  1. The partner "Clients" portal — where a reseller creates the merchant account and sends login credentials.
  2. The merchant back-office — where the Hendrickx POS is actually connected and the menu synced (route /hendrickx, handled by KassanetIntegrationController). There is no reseller-specific Hendrickx connect screen; the connection is made in the merchant's own back-office (which a partner can enter on the merchant's behalf).

The end-to-end mechanics of the integration itself (encryption, order push, table allocation, logs, etc.) are documented in Hendrickx Integration and Kassanet Integration. This page covers only the onboarding/reseller-facing flow.


Reseller Surface (How a Partner Manages Merchants)

The reseller system in the back-office splits roles into a global level and a reseller level (App\Constants\Roles):

  • Global Administrator — creates and manages reseller companies, assigns/unassigns merchants to a reseller, and manages reseller users. All /back-office/admin/resellers/* routes are gated to global-administrator only (checked in ResellerController).
  • Reseller Owner / Reseller Administrator (the "partner") — can create new merchants for their own reseller and send them credentials, and manage their clients' billing/subscriptions.

What a partner can do (verified)

ActionWhere (back-office route)APIAuthorization
Create a merchant ("client")Clients portal (src/pages/clients/, ClientFormDialog.vue)POST /back-office/partner/merchants (ResellerController::createMerchant)isGlobalUser — i.e. global admin or reseller-owner/reseller-administrator (CreateMerchantRequest::authorize)
Send login credentials to a merchantClient detail pagePOST /back-office/partner/merchants/{merchantId}/send-credentials (sendMerchantCredentials)Global user; a reseller is restricted to merchants whose reseller_id matches their own
View / manage a client's subscriptions & invoicesClient detail page/back-office/reseller/{resellerId}/billing/* (ResellerBillingController)Reseller billing routes
See which POS providers their reseller supportsUsed by Emily onboardingGET /back-office/merchant/reseller-providers (getMerchantResellerProviders)Current merchant's reseller

When a partner creates a merchant, the backend (ResellerService::createMerchant):

  • Creates the merchant + owner user (first_name, last_name, email, password, optional business_name/phone, required locale).
  • Sets reseller_id to the partner's reseller, onboarding_type = reseller, merchant_status = New, and stripe_onboarding_completed = true.
  • Flags the new user must_change_password = true (the merchant changes it on first login).
  • If the creator is a reseller, adds the new merchant to the partner user's vendor_ids so the partner can act on its behalf.

A reseller can act on behalf of one of its merchants (merchant switching exists via POST /back-office/set-merchant), and PermissionService::hasPermission explicitly allows a reseller to operate on a merchant it has access to. The connect-Hendrickx steps below are then performed inside that merchant's back-office.

What a partner cannot do

  • Creating, updating, or deleting reseller companies, assigning/unassigning merchants to a reseller, listing all merchants, and managing reseller users are Global Administrator only.
  • There is no separate "reseller onboarding wizard" for the POS connection — the merchant (or the partner on its behalf) uses the standard back-office flow and Emily Guided Setup.

Connecting Hendrickx (in the merchant back-office)

The actual POS connection happens at route /hendrickx in the merchant back-office (frontend src/pages/hendrickx/, dialog HendrickxChannelDialog.vue). The backend route group is POST/GET /api/back-office/kassanet/{provider}/{locationId} with {provider} = hendrickx, served by KassanetIntegrationController.

Prerequisites (verified)

  • Branding profile — the only profile enforced at connect time. ThirdPartyIntegrationHelper::checkRequiredProfiles requires a branding profile for Hendrickx; payment and billing profiles are optional and can be set up later.
  • A location must exist and be selected in the topbar before connecting (the connection is location-scoped).
  • The menu must already exist in Hendrickx. Menu sync is one-way (Hendrickx → Upvendo); Upvendo cannot create items in the POS.
  • No other in-house POS on the location/merchant. A location may have only one in-house POS. Hendrickx, Vanhoutte, and ShopCaisse are mutually exclusive per location and also conflict with the merchant-scoped in-house POS (Square, MplusKassa, Lightspeed). A conflict aborts with HTTP 400 "Another in-house channel is already enabled for this merchant" (ThirdPartyIntegrationHelper::checkForInhouseChannel).

Credentials (3 fields + optional sync time, verified)

The connect form (HendrickxForm.vue) and InitiateKassanetRequest accept exactly:

  • Connection URL (base_url) — required, validated as a URL. The Hendrickx OrderConnector / Kassanet API base URL.
  • Signature Key (signature_key) — required string. HMAC-SHA256 signing key.
  • Encryption Token (encryption_token) — required string. Blowfish encryption key.
  • Daily Sync Time (sync_time) — optional. Must be HH:00 or HH:30 (minutes restricted to 00/30). The value is the local time at the location, stored as that local wall-clock time, so it stays put across daylight-saving changes. The form shows the resolved timezone as a caption under the field ("Runs in the ... timezone"); the merchant does not pick it. Clear it to disable auto-sync.

Saving the form connects the integration and auto-triggers a menu sync. (Encryption is controlled by an enable_encryption flag that defaults to on, not a field on this form.)


Onboarding Steps (Emily Guided Setup)

Once the merchant logs in, onboarding is driven by Emily Guided Setup (see Guided Setup). The wizard either uses dynamic steps generated by Emily during a discovery conversation, or falls back to a built-in per-POS checklist (BASE_SETUP_STEPS in src/components/dialogs/guided-setup/types.ts). The production PRODUCTION_POS_PROVIDERS list is Upvendo POS, Hendrickx and Vanhoutte — though Upvendo POS is staged test_only server-side (config/pos-providers.php:51-52 — production offers it only to test-flagged merchants) and the grid rendering these constants is not reachable in the shipped app.

During discovery Emily can scope onboarding to one or more channels (Kiosk only, Online ordering only, or Both), which determines whether the Kiosk and/or Online Ordering channel checklists are added after the base steps.

Base steps for Hendrickx (verified, BASE_SETUP_STEPS['hendrickx'])

setup_steps
{
  "base": [
    {"id": "payment_profile", "title": "Set up Payment Profile", "route": "/settings/payments", "optional_for_go_live": true},
    {"id": "billing_profile", "title": "Set up Billing Profile", "route": "/settings/billing", "optional_for_go_live": true},
    {"id": "branding_profile", "title": "Set up Store Branding", "route": "/settings/brand"},
    {"id": "create_location", "title": "Create Location", "route": "/settings/locations"},
    {"id": "select_location", "title": "Select Location from Topbar", "action": "open_location_selector"},
    {"id": "connect_pos", "title": "Connect Hendrickx", "route": "/hendrickx", "channel": "hendrickx"},
    {"id": "sync_menu", "title": "Sync Menu", "route": "/hendrickx"}
  ],
  "kiosk_channel_steps": [
    {"id": "menu_for_kiosk", "title": "Build Menu for Kiosk", "route": "/menus/menu-builder"},
    {"id": "in_house_settings", "title": "Set up In-House Settings", "route": "/in-house/settings"},
    {"id": "device_profile", "title": "Create Device Profile", "route": "/device-management/profiles"},
    {"id": "kiosk_device", "title": "Set up Kiosk & Activate Payment", "route": "/device-management/devices"},
    {"id": "test_kiosk", "title": "Activate Kiosk & Test Order"}
  ],
  "online_ordering_channel_steps": [
    {"id": "menu_for_online_ordering", "title": "Build Menu for Online Ordering", "route": "/menus/menu-builder"},
    {"id": "online_settings", "title": "Set up Online Settings", "route": "/online-settings"},
    {"id": "configure_online_ordering", "title": "Set up Online Ordering", "route": "/online/online-ordering"},
    {"id": "test_online_ordering", "title": "Open Online Ordering URL & Test Order", "route": "/online/online-ordering"}
  ]
}

Notes on the base steps:

  • Of the base profile steps, only Store Branding is enforced at connect time. Payment Profile and Billing Profile are part of the checklist for completeness but are optional for connecting Hendrickx.
  • The "Select Location from Topbar" step is an action (open_location_selector), not a navigation route.
  • "Connect Hendrickx" and "Sync Menu" both point at /hendrickx.
  • Completion is auto-detected from the merchant's real data via GET /back-office/setup-status — the merchant does not tick steps off manually. "Connect Hendrickx" is only marked complete when the integration is both connected and has a successful test.

Channel steps

The Kiosk and Online Ordering checklists are shared across POS providers (KIOSK_CHANNEL_STEPS, ONLINE_ORDERING_CHANNEL_STEPS) and appear after the base steps via a "Continue to Channel Setup" action. Kiosk device setup lives under /device-management/profiles and /device-management/devices; online ordering is configured at /online/online-ordering with settings at /online-settings.


Payments

After menu sync, orders are pushed to Hendrickx only after the customer pays. Upvendo collects the payment and Kassanet records the tender on the POS bill:

  • Kiosk — Viva Wallet (terminal).
  • Online Ordering / Table QR — Stripe.

Setting up a payment profile is required to accept customer payments, but is not required to connect Hendrickx. (Payment specifics: see Hendrickx Integration.)


Discovery Notes

The structured discovery question/answer flow (channel selection, menu-readiness check) is conducted by Emily through the onboarding proxy, not by a static configuration in the back-office or Emily back-office code in these repositories. The underlying constraints it is based on are code-true:

  • Menu must exist in Hendrickx first — confirmed by the one-way menu sync (Hendrickx → Upvendo only). If the merchant has no menu in Hendrickx, there is nothing to import; they must build it in the POS before connecting.
  • Channel choice (Kiosk / Online ordering / Both) — confirmed: it determines which channel checklist(s) are appended (EmilyWidget.vue, EmilySetupPanel.vue).

Not verified here: the exact wording, ordering, and abort behaviour of Emily's discovery prompts (these live in the Emily/onboarding proxy and knowledge base, not in upvendo-backend or upvendo-backoffice).


FAQs

Q: How does a reseller add a new merchant? A: From the partner Clients portal, using the "create client" form (name, email, password, optional business name/phone, required locale). This calls POST /back-office/partner/merchants. The merchant is created with onboarding_type = reseller and must_change_password = true, and is linked to the reseller via reseller_id. The partner can then send login credentials.

Q: Can a reseller connect Hendrickx for the merchant? A: The connection is made in the merchant's back-office at /hendrickx. A partner with access to the merchant can act on its behalf (merchant switching) and perform the same flow; there is no separate reseller-only connect screen.

Q: What credentials are needed to connect Hendrickx? A: Three: Connection URL (base_url), Signature Key (signature_key), and Encryption Token (encryption_token), plus an optional daily Sync Time (HH:00/HH:30, read as the location's local time).

Q: Which profiles must be set up before connecting? A: Only a branding profile is enforced. Payment and billing profiles are optional and can be added later (payment is required before taking customer payments).

Q: Can a location run Hendrickx plus another POS? A: No. One in-house POS per location. Hendrickx, Vanhoutte, and ShopCaisse are mutually exclusive per location and conflict with merchant-scoped Square/MplusKassa/Lightspeed.

Q: Who can create reseller companies and assign merchants to them? A: Global Administrators only. Reseller owners/administrators can create merchants for their own reseller and manage their clients' billing, but not other resellers or the reseller-company records themselves.