Skip to content

Backoffice → Kiosk Relations

How backoffice settings flow to the Kiosk self-service device.

Overview

Kiosks are self-service ordering terminals (Android tablets) placed in-store. A kiosk's behaviour is driven almost entirely by the device profile assigned to it, plus the kiosk's location settings (tipping, languages, receipt content, notes) and the location's branding profile (Settings → Brand, /settings/brand), which supplies the kiosk's logos, fonts and colours. Menus reach the kiosk through the profile, not the device. Most settings are pushed to the device by a ReloadMenu re-sync event rather than requiring a restart.

┌─────────────────────────────────────────────────────────────────────────┐
│                           BACKOFFICE                                     │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │
│  │   Device    │ │    Menus    │ │  Location   │ │  Payments   │       │
│  │  Profiles   │ │             │ │ (collect_   │ │ (per-device │       │
│  │             │ │             │ │   tips)     │ │  terminal)  │       │
│  └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘       │
└─────────┼───────────────┼───────────────┼───────────────┼───────────────┘
          │               │               │               │
          ▼               ▼               ▼               ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                            KIOSK                                         │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │
│  │   Device    │ │    Menu     │ │   Tips /    │ │  Payment    │       │
│  │   Config    │ │   Display   │ │   Dining    │ │  Terminal   │       │
│  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │
└─────────────────────────────────────────────────────────────────────────┘

The kiosk app (upvendo-kiosk) is an Android client. How it visually renders any of these values (layouts, copy, transitions) is not verified here; this doc maps the back-office settings and the backend data that drive the kiosk.

How a kiosk is configured

A kiosk device (Device, type Kiosk) carries only a handful of its own fields — its name, its location_id, an optional device_profile_id, and its paired payment terminal. Everything about the ordering experience (menus, dining options, idle behaviour, screensaver, schedule, receipt handling, customer flow, order-number display) lives on the device profile it points at. The menu is not set on the device.

Device-level settingFieldKiosk impact
Device NamenameIdentifier in the back office / reports (unique per merchant)
Assigned Locationlocation_idWhich location's data, in-house settings, and tipping the kiosk uses
Device Profiledevice_profile_idThe profile that supplies menus and all kiosk settings (optional)
Payment Terminalviva_wallet_terminal_id / stripe_terminal_id / external_data.squareThe card reader paired to this device, per payment provider

See Kiosk Setup, Device Profiles, and Payments.


Device Profile → Kiosk

These are the actual fields on a device profile (app/RawModels/DeviceProfile.php, validated by StoreDeviceProfileRequest). Each profile is location-scoped and its device type is hardcoded to Kiosk. Saving a profile fires a ReloadMenu event so assigned devices re-sync.

Profile settingField(s)Kiosk impact
Default Menucustom_default_menu, default_menu_idThe menu served to the kiosk. When custom_default_menu is off, the location's in-house default menu is used; when on, default_menu_id applies.
Extra Menusextra_menu_idsAdditional menus served alongside the default. When custom_default_menu is on, the profile's own extra_menu_ids are used; when it is off, the location's in-house extra_menu_ids are used instead (DeviceProfile::getExtraMenus() DeviceProfile.php:316-337). Only the profile-owned list is editable in the profile form.
Dining Option 1 / 2dining_option_1, dining_option_2Two slots, each For Here, Takeout, or None; the two must differ. A slot set to None removes that choice.
Custom dining picturesuse_custom_pictures_for_dining_options, dining_option_1/2_content_idWhen on, custom images per non-None dining option; otherwise default plate/shop images.
Idle Timeoutidle_timeout_type, idle_timeout_seconds, show_warning_for_secondsEnds an idle session and clears entered data. Standard = warning after 45 s, shown 15 s (fixed by backend); Custom = your own values (min 1 s each).
Idle Screensaveridle_screensaver.enabled, idle_screensaver.minutes, screensaver_content_idOptional full-screen image after N idle minutes. Separate from the idle timeout.
Menu Item Columnsmenu_item_columnsItem grid layout: 2 or 3 columns (default 2).
Order Number Displayorder_number_displayWhat the customer sees after ordering: queue_number, order_number, or both (default both).
Customer Identificationallow_customer_identification, customer_identification_methodsWhen on, customers can identify via the enabled methods: member_code (default on), email, phone. With loyalty active, identified customers see points/rewards.
Sell Without Stocksell_without_stockWhether out-of-stock items can still be ordered (toggle shown only when the location tracks inventory).
Use Pageruse_pager, pager_instructionsWhether the kiosk hands out a pager plus the title/subtitle instructions shown.
Reset Language On Completereset_language_on_order_completeWhether the kiosk resets to the default language after an order completes.
Receipt Optionsreceipt_options.print/email/phone, auto_print_receiptWhich receipt-delivery options are offered (defaults print: true, email: true, phone: false) and whether receipts auto-print.
Section Selectionsection_selection_enabled, section_idsWhen on, the customer picks a section/table (section_ids required, max 6).
Order Instructionsorder_instructions.*Optional instruction text shown to the customer — one message for all, or separate per dining option.
Device Scheduleschedule_type, scheduleWhen the kiosk is active: Default (location hours), Custom (per-day ranges), or Deactivated.

Fields that do NOT exist on a device profile: there is no theme/dark-mode toggle, no language list/default-language, no "show images"/image-size, no category-layout, no "upsell enabled", no "tips enabled", and no screensaver media-type or "schedule enabled" toggle. That does not mean the kiosk has no visual theming — colours, fonts and logos come from the location's branding profile (below), not the device profile. Tipping, upsells, languages, receipt content, and notes all come from elsewhere too (below).

Tipping is a location setting, not a profile field

Tip collection is not a device-profile field. The kiosk reads tipping from the location's in-house settings collect_tips object. When the kiosk menu data is generated, tipping_enabled is taken from location->getInHouseSetting()['collect_tips']['enabled'] (DeviceProfile::generateMenuData()). For Kassanet-integrated menus (Hendrickx / Vanhoutte) this is further gated by the POS tipCalculatorActivated flag from the Kassanet API. See Tips.

Backoffice settingFieldKiosk impact
Collect Tips (location in-house)in_house_setting.collect_tips.enabledWhether the kiosk offers a tip step
Tip Optionscollect_tips.options (default [10, 15, 20])Percentage buttons shown
Calculate Tipscollect_tips.calculate_tipsStored preference (After taxes / Before taxes) — never read by any pricing code. The real tip base is country-dependent: US = pre-VAT (totalExcludingVAT), non-US = VAT-inclusive post-discount (totalBeforeTip) (TransactionService.php:1225, :712). Kassanet (Hendrickx / Vanhoutte) menus use the same base without subtracting the discount (TransactionService.php:694).

Upsells are a separate feature

Upsell suggestions on the kiosk are not a device-profile toggle. They are configured as Upsell Groups (Marketing → Upsell Groups), scoped per location, and served to the location's ordering channels. See Upsell Groups. (Channel-side rendering on the kiosk is not verified here.)

Languages come from Settings → Languages

The kiosk's language list is not a profile field. genKioskDetails() ships languages[] — every Language record with status Published in the merchant's tenant database (Device::getMerchantData() Device.php:967) — and default_language, taken from Location::getPreferredLanguage() (Device.php:921). Both are typed on the kiosk side as languages / default_language (upvendo-kiosk/src/types/auth.ts:14-15). Configured at Settings → Languages (/settings/languages). The profile's only language-related field is reset_language_on_order_complete.

Receipt content comes from Settings → Receipts

Location::getReceiptSetting() is pushed to the kiosk as receipt_settings (Device.php:929), configured at Settings → Receipts (/settings/receipts). This is distinct from the profile's receipt_options / auto_print_receipt, which only decide which delivery options are offered and whether receipts auto-print.

Notes come from the location's in-house settings

allow_notes (per-item notes) and allow_order_notes (order-level notes) reach the kiosk from the location's in-house settings, not the device profile (Device.php:1025-1027). They are gated independently; a device saved before the split has no allow_order_notes and falls back to allow_notes.


Branding → Kiosk

The kiosk's look comes from the location's branding profile, not from the device profile. Device::genKioskDetails() merges a branding block built by getBrandingData() from Location::getBrandingProfile() (Device::getBrandingData(), Device.php:854-885, merged into genKioskDetails() at :1049), which the kiosk consumes as ShopDetails.branding (upvendo-kiosk/src/types/auth.ts:93-109). Configured at Settings → Brand (/settings/brand, individual profiles at /settings/brand/profiles/:id).

Branding-profile fieldKiosk effect
logo_urlBrand logo shown in the kiosk UI
receipt_logo_urlLogo embedded on printed/emailed receipts (base64)
favicon_urlIcon for the web/browser build
banner_urlBanner image asset
heading_text_fontFont used for headings
body_text_fontFont used for body text
primary_colorPrimary brand colour
secondary_colorSecondary brand colour
primary_text_colorPrimary text colour
secondary_text_colorSecondary text colour
primary_background_colorPrimary background colour
secondary_background_colorSecondary background colour
promo_code_fontFont for promo-code display
promo_code_font_colorText colour for promo-code display
promo_code_background_colorBackground colour for promo-code display

Alongside branding, the payload also carries primary_color_palette from the same profile (Device.php:885). Exactly how the kiosk app applies each value on screen is not verified here.


A menu reaches a kiosk only through the device profile. The menu itself does not carry a "default menu" flag — that relationship is set on the profile (default_menu_id / extra_menu_ids).

Backoffice settingKiosk impact
Menu visibility includes KioskThe menu is eligible to appear on kiosks for that location
Item name / description / price / imageRendered on item cards (kiosk-app rendering not verified here)
Item availability / stockHidden or shown as unavailable; sell_without_stock on the profile governs ordering out-of-stock items
Allergens / dietary preferencesStored per item and served to the kiosk
Display groups & orderThe grouping/order of items the customer browses

Backend guards protect live kiosks: a menu used by a kiosk profile that has active devices cannot be set to Draft/Archive, and its Kiosk visibility cannot be removed (both return HTTP 400). See Menus, Menu Items, and Modifiers.


Payments → Kiosk

Kiosk/in-person card payments use the location's in-person provider. A terminal is paired per device, not on the payment profile.

Backoffice settingFieldKiosk impact
Viva Wallet terminal (default in-person provider)viva_wallet_terminal_idKiosk takes card payments through that Viva terminal
Stripe Terminal reader (Stripe in-person)stripe_terminal_idPaired reader the kiosk uses for card payments
Square Terminal (when Square POS connected)external_data.squareSquare handles payments; profiles/Stripe/Viva are bypassed
Test mode (per location)payment_test_mode (on the location)Simulated payments, no real charge

There is no single "terminal" select with a "None" option — a device simply has no terminal paired until one is added, and each device has one paired reader at a time. See Payments.

Kiosk payment flow (backend-confirmed):

Customer completes order


Tips step (only if the location's collect_tips.enabled is true)


Payment:
├── Card → terminal activated (Viva / Stripe reader / Square)
│          status updates published to the device via Firebase
│          (Submitting → Processing → Succeeded / Failed / Canceled)

└── Free order (total 0) → no provider, marked complete automatically


Order confirmation (queue/order number per order_number_display)

Kiosk transactions are idempotency-keyed: if a completed transaction already exists for a given idempotency key, the existing order is returned instead of creating a duplicate.


Dining Options

Each profile has two dining-option slots, each chosen from For Here, Takeout, or None (DiningOptions::deviceProfile()). The two slots must differ. Setting one slot to None means the customer is not asked to choose and all orders take the other option.

For Here (Dine In)

Profile: dining_option_1 or dining_option_2 = "For Here"

Kiosk: "For Here" choice available (skipped if the other slot is None)

Customer selects → order labelled "For Here"

Takeout

Profile: dining_option_1 or dining_option_2 = "Takeout"

Kiosk: "Takeout" choice available (skipped if the other slot is None)

Customer selects → order labelled "Takeout"

Remote Control (FCM)

The back office can send remote-control commands to a kiosk over Firebase Cloud Messaging (FCM). Commands are delivered to all FCM tokens registered for that device and only apply to Kiosk-type devices (DeviceService::remoteControl() returns early for any non-Kiosk device).

CommandValue (RemoteControlCommands enum)
Restartrestart
Logoutlogout
Firmware updatefirmware_update
Update APKupdate_apk

Device Status (Online / Offline)

A kiosk's status is derived (Device::getStatus()), not stored as a free-text field. The DeviceStatuses enum also defines Needs Attention and Critical Issue, but kiosk status resolves to Online or Offline:

  • Offline if the device is not activated, has never checked in (last_seen_at null), has is_online === false, or was last seen longer ago than the offline threshold.
  • Online if it is activated and was seen within the threshold (devices.offline_threshold_seconds, default 900 s / 15 minutes).

Real-Time Sync

Pushed to the device on save (ReloadMenu re-sync)

  • Menu assignment and content (default + extra menus, display groups, items)
  • Device profile settings (dining options, idle behaviour, screensaver, schedule, receipt options, customer flow, order-number display)
  • Item availability and stock

Saving or updating a device profile, or updating/reordering a menu, dispatches a ReloadMenu event for the location so assigned kiosks re-sync their configuration and menu data. (A device restart is not required for these changes.)

Sent over FCM (real time)

  • Remote-control commands (restart / logout / firmware update / update APK) — DeviceService::remoteControl()SendFcmBroadcastJob (DeviceService::remoteControl, DeviceService.php:1500-1508)

Sent over Firebase Realtime Database

  • Kiosk payment status at devices/{deviceId}/payment-status (Submitting / Processing / Succeeded / Failed / Canceled), plus queue_number / order_number / receipt_no / payment_method once each is known — FirebaseTrait::publishPaymentStatus() (FirebaseTrait::publishPaymentStatus, FirebaseTrait.php:43). This is not FCM.

Via the kiosk transaction API

  • Order submission (idempotency-keyed)
  • Payment processing
  • Receipt handling

Troubleshooting

Kiosk Not Showing a Menu

Possible Causes:

  • No device profile assigned, or the profile has no default menu
  • If the profile uses a custom default menu, default_menu_id is not set
  • The menu's visibility does not include Kiosk, or the menu has no items
  • Network connectivity issue

Backoffice Check:

  1. Device Management → Devices → confirm a device profile is assigned
  2. Device Management → Profiles → confirm the default menu (or that the location's in-house default menu exists)
  3. Menus → confirm the menu includes the Kiosk channel and has items

Payment Terminal Not Working

Possible Causes:

  • No terminal paired to the device
  • Terminal offline or wrong terminal paired
  • Network issue

Backoffice Check:

  1. Device Management → Devices → open the device → Reader / Terminal section
  2. Verify the terminal is online in the provider dashboard (Viva / Stripe / Square)

Kiosk Shows Offline

Possible Causes:

  • Device not activated or hasn't checked in
  • Not seen within the offline threshold (default 15 minutes)
  • Network/power problem

Backoffice Check:

  1. Confirm the device is activated and powered on
  2. Check the device's connectivity; status returns to Online once it checks in within the threshold

Tips Not Showing on the Kiosk

Possible Causes:

  • collect_tips.enabled is off in the location's in-house settings (tipping is not a profile field)
  • For Kassanet (Hendrickx / Vanhoutte) locations, the POS tipCalculatorActivated flag is off

Backoffice Check:

  1. In-House Settings → Collect Tips → enable and set options
  2. For Kassanet locations, confirm tipping is enabled on the POS side