Appearance
Device Profiles
Overview
Device Profiles are reusable configuration templates assigned to kiosk devices. Instead of configuring each kiosk individually, you create a profile once and assign it to one or more devices at a location. The profile controls the kiosk's menus, dining options, idle behaviour, screensaver, schedule, receipt options, customer flow, customer identification, and order-number display.
Key Purpose: Create reusable configuration templates for kiosk devices.
Purpose
This page lets you create and manage configuration profiles that drive the kiosk experience: dining options, default and extra menus, idle settings, schedule, receipt handling, customer-flow layout, customer identification, and order-number display.
Key Concepts
- Device Profile: A named, location-scoped configuration template assigned to one or more devices. Each profile is created for a specific
location_id. - Profile family selector: The New Device Profile dialog renders a family selector. The Kiosk family is always offered and still creates a profile whose
typethe backend hardcodes toDeviceTypes::Kiosk(app/Services/BackOffice/DeviceProfileService.phpline 71). A second family, Kitchen Display, appears in that selector only when the merchant is running the first-party Upvendo POS (isFirstPartyPosActive()); it creates a separateKdsProfilemodel (typefixed toDeviceTypes::KitchenDisplay) through its own/back-office/kds-profilesroutes and opens the shared editor with?type=kdsto show the KDS-only sections (Prep & Orders, Timers, Sound). The selector control itself renders for everyone — a non-first-party merchant simply sees a single Kiosk option. POS profiles do not exist in this surface at all: the family map enumerates only kiosk, printer and KDS. Printer profiles are no longer options-only, but they are not managed here either — they have their own page, Device Management → Printer Profiles (/device-management/printer-profiles), gatedfirstPartyPosOnlyon top of the samedevice-profilepermissions. See Printers. (Verified:upvendo-backoffice/src/views/device-profiles/forms/components/NewDeviceProfileDialog.vuelines 36-49, the KDS entry added only whenisFirstPartyPosActive()at line 43;src/utils/deviceProfileFamily.tslines 12-31;src/views/device-profiles/forms/kds/containsPrepAndOrders.vue,Timers.vue,Sound.vue,KdsDurationField.vue;app/RawModels/KdsProfile.phpline 169;routes/api/backoffice/kds-profiles.phplines 31-49.) - Where the KDS gate leaks: hiding the create option is not the whole gate. The profile list's type filter always offers "Kitchen Display", to every merchant — it is appended to the server's options list unconditionally. Selecting it together with a location switches the table to
/back-office/kds-profiles, which is behind thefirst-party-posmiddleware, so a non-first-party merchant gets a 403 and the back office shows the backend's message, "This feature is only available to merchants using the first-party Upvendo POS." So: for a non-first-party merchant the KDS profile family cannot be created (no option in the dialog) but can be navigated to from the filter, where it errors rather than showing an empty table. (Verified:upvendo-backoffice/src/views/device-profiles/DeviceProfiles.vuelines 131-135 buildtypeOptionswith no first-party check, lines 125-126 and 154-161 switch the source;app/Http/Middleware/EnsureFirstPartyPos.phplines 42-53.) - Dining Options: Each profile has two slots,
dining_option_1anddining_option_2, each chosen from For Here, Takeout, or None. The two slots must differ. - Idle Timeout: Ends an in-progress session and clears entered data after inactivity. Standard uses the backend-returned values (warning after 45s, shown for 15s); Custom lets you set both values (minimum 1 second each).
- Idle Screensaver: A separate, optional full-screen image shown on an untouched kiosk after a configured number of minutes — distinct from the idle timeout.
- Device Schedule: Controls when the kiosk is active — Default follows the location's hours, Custom uses per-day time ranges, Deactivated turns scheduling off.
- ReloadMenu Event: Saving (create or update) a profile fires a
ReloadMenuevent so assigned devices re-sync their configuration and menu data.
Actions
Create Device Profile
Navigate to Device Management → Device Profiles, then add a new profile. Enter a unique name, pick the location, configure the two dining options, set up default and optional extra menus, choose idle settings, optionally enable the screensaver, set the schedule, and configure the remaining customer-flow / receipt / identification options. Requires the create-device-profile permission.
Edit Device Profile
Open an existing profile to modify its settings. Saving fires a ReloadMenu event so assigned devices re-sync. The profile's Assigned Devices section (visible only when editing) lists the devices currently using it. Requires the edit-device-profile permission.
Delete Device Profile
Remove a profile. Deletion is blocked while any device is still assigned to it — all devices must be reassigned first. Requires the delete-device-profile permission.
Configure Menus
Add a default menu and optionally extra menus served alongside it. When the profile's "override default menu" toggle is off, the location's in-house default menu is used; when on, the profile's own default_menu_id (and any extra_menu_ids) apply.
Enable Idle Screensaver
Turn the idle screensaver on, set the number of minutes of inactivity before it appears, and upload a screensaver image. The screensaver shows on an untouched kiosk; it is separate from the idle timeout that resets the session.
Business Rules
- Profile names are validated for uniqueness within the tenant connection (
UniqueInConnectionWithModel). dining_option_1anddining_option_2must be different. The request computesis_dining_option_valid = (dining_option_1 !== dining_option_2); if they are equal, validation fails with "The dining options is invalid."- Dining-option values are restricted to
DiningOptions::deviceProfile()= For Here, Takeout, None. - When Use custom pictures is on, an image is required for each dining-option slot that is not None (max 10 MB each).
- Idle timeout:
idle_timeout_typeisstandardorcustom. Forcustom, bothidle_timeout_secondsandshow_warning_for_secondsare required and must be at least 1. - Idle screensaver: when
idle_screensaver.enabledis true,idle_screensaver.minutesand an uploaded screensaver image are required. - Schedule:
schedule_typeisDefault,Custom, orDeactivated. ForCustom, each day requires anis_availableflag and, when available,timesentries withfrom/toinH:iformat. menu_item_columnsmust be2or3(defaults to2).order_number_displaymust bequeue_number,order_number, orboth.- Profile deletion is blocked when
getDeviceCount() > 0, aborting with HTTP 400 and the message "Profile is still used by devices."
Location
- Backoffice Route:
/device-management/profiles(route namedevice-management-profiles; create at/new-profile, edit at/edit/:id) - Navigation: Device Management → Device Profiles (
device-profiles.nav-title, subjectdevice-profile) - Backend Controller:
app/Http/Controllers/Api/BackOffice/DeviceProfileController.php - Backend Routes:
routes/api/backoffice/device-profiles.php(prefix/back-office/device-profiles) - Backend Model:
app/RawModels/DeviceProfile.php - Backoffice Page:
src/pages/device-management/profiles/index.vue - Backoffice Form:
src/views/device-profiles/DeviceProfileForm.vue(sub-forms insrc/views/device-profiles/forms/) - Backoffice Store:
src/store/modules/deviceProfile.ts
Fields
Profile Name
| Property | Value |
|---|---|
| Field ID | name |
| Label | Profile Name |
| Type | Text |
| Required | Yes |
| Validation | Unique within the tenant connection |
Description: Name for this configuration profile.
Location
| Property | Value |
|---|---|
| Field ID | location_id |
| Label | Location |
| Type | Select |
| Required | Yes (on create) |
Description: The location this profile belongs to. Required when creating a profile (exists:locations,_id); not changed on edit.
Default Menu
| Property | Value |
|---|---|
| Field ID | default_menu / default_menu_id (with custom_default_menu) |
| Label | Default Menu |
| Type | Menu selector |
Description: The menu served to kiosks using this profile. When custom_default_menu is off the profile falls back to the location's in-house default menu; when on, default_menu_id is required and used.
Extra Menus
| Property | Value |
|---|---|
| Field ID | extra_menus / extra_menu_ids |
| Label | Extra Menus |
| Type | Menu list |
Description: Additional menus served alongside the default menu. Only applicable when custom_default_menu is on (extra_menu_ids.* are required strings).
Dining Option 1
| Property | Value |
|---|---|
| Field ID | dining_option_1 |
| Label | Dining Option 1 |
| Type | Select |
| Options | For Here, Takeout, None |
| Required | Yes |
Description: First dining-option slot. Must differ from dining_option_2.
Dining Option 2
| Property | Value |
|---|---|
| Field ID | dining_option_2 |
| Label | Dining Option 2 |
| Type | Select |
| Options | For Here, Takeout, None |
| Required | Yes |
Description: Second dining-option slot. Must differ from dining_option_1.
Use Custom Pictures for Dining Options
| Property | Value |
|---|---|
| Field ID | use_custom_pictures_for_dining_options |
| Label | Use Custom Pictures |
| Type | Toggle |
| Default | false |
Description: When on, you can upload an image for each non-None dining option (dining_option_1_image, dining_option_2_image; max 10 MB each). Stored as dining_option_1_content_id / dining_option_2_content_id.
Idle Timeout
| Property | Value |
|---|---|
| Field ID | idle_timeout_type, idle_timeout_seconds, show_warning_for_seconds |
| Label | Idle Settings |
| Type | Radio (Standard / Custom) + Number (seconds) |
| Options | standard, custom |
| Default | standard (seconds 45 / warning 15) |
Description: Ends an in-progress session and clears entered data after inactivity.
Business Logic:
- Standard: warning after 45 seconds, shown for 15 seconds (backend-returned values).
- Custom: set
idle_timeout_seconds("give warning after") andshow_warning_for_seconds("show warning for"); both required, minimum 1.
Idle Screensaver
| Property | Value |
|---|---|
| Field ID | idle_screensaver.enabled, idle_screensaver.minutes, screensaver_image (stored as screensaver_content_id) |
| Label | Idle Screensaver |
| Type | Toggle + Number (minutes) + Image upload |
| Default | Off (minutes: null) |
Description: An optional full-screen image shown on an untouched kiosk after the configured idle minutes. Separate from the idle timeout. When enabled, both minutes and an uploaded image are required.
Menu Item Columns
| Property | Value |
|---|---|
| Field ID | menu_item_columns |
| Label | Menu Layout |
| Type | Select |
| Options | 2, 3 |
| Default | 2 |
Description: Number of columns used to lay out menu items in the customer flow.
Order Number Display
| Property | Value |
|---|---|
| Field ID | order_number_display |
| Label | Order Number Display |
| Type | Radio |
| Options | queue_number, order_number, both |
| Default | both |
Description: Which identifier is shown to the customer after an order is placed — queue number, order number, or both.
Customer Identification
| Property | Value |
|---|---|
| Field ID | allow_customer_identification, customer_identification_methods |
| Label | Customer Identification |
| Type | Toggle + method checkboxes |
| Methods | member_code (default on), email, phone |
| Default | Off |
Description: When enabled, customers can identify themselves using the enabled methods. With loyalty active, identified customers see their points and rewards. (Kiosk-app behaviour: not-verified-here.)
Sell Without Stock
| Property | Value |
|---|---|
| Field ID | sell_without_stock |
| Label | Sell Without Stock |
| Type | Toggle |
| Default | false |
Description: Whether out-of-stock items can still be ordered. The toggle is shown only when the location has tracked inventory.
Reset Language On Order Complete
| Property | Value |
|---|---|
| Field ID | reset_language_on_order_complete |
| Label | Reset Language On Order Complete |
| Type | Toggle |
| Default | false |
Description: Whether the kiosk resets to the default language after an order completes.
Use Pager
| Property | Value |
|---|---|
| Field ID | use_pager, pager_instructions |
| Label | Use Pager |
| Type | Toggle + instructions (title max 200, subtitle max 300) |
| Default | false |
Description: Whether the kiosk hands out a pager, plus the title/subtitle instructions shown to the customer (only when on).
Receipt Options
| Property | Value |
|---|---|
| Field ID | receipt_options.print, receipt_options.email, receipt_options.phone, auto_print_receipt |
| Label | Receipt Settings |
| Type | Checkboxes + Auto-print toggle |
| Default | print: true, email: true, phone: false; auto_print_receipt: false |
Description: Which receipt-delivery options are offered and whether receipts auto-print. The manual print option is hidden when auto_print_receipt is on.
Section Selection
| Property | Value |
|---|---|
| Field ID | section_selection_enabled, section_ids |
| Label | Section Selection |
| Type | Toggle + section list (max 6) |
| Default | Off |
Description: When enabled, the kiosk lets the customer pick a section/table. section_ids is required when enabled.
Order Instructions
| Property | Value |
|---|---|
| Field ID | order_instructions.enabled, order_instructions.use_same_for_all, order_instructions.all, order_instructions.for_here, order_instructions.takeout |
| Label | Order Instructions |
| Type | Toggle + textareas (max 300 each) |
| Default | enabled: false, use_same_for_all: true |
Description: Optional instruction text shown to the customer — either one message for all orders, or separate text per dining option.
Device Schedule
| Property | Value |
|---|---|
| Field ID | schedule_type, schedule |
| Label | Schedule |
| Type | Radio (Default / Custom) + per-day time ranges; Deactivated via separate action |
| Options | Default, Custom, Deactivated |
| Default | Default |
Description: When the kiosk is active. Default follows the location's hours; Custom uses per-day is_available + times (from/to, H:i); Deactivated turns scheduling off.
Note on tipping: Tip collection is not a device-profile field. Tipping is read from the location's in-house settings (
collect_tips). ATipping.vuecomponent exists in the source tree but is not wired into the profile form.
Business Logic
Profile Lifecycle
Create / edit profile (location-scoped, type hardcoded to Kiosk)
│
▼
Validate (StoreDeviceProfileRequest)
│
▼
Store / update via DeviceProfileService
│
▼
Fire ReloadMenu(location_id, "device_profile", profile_id)
│
▼
Assigned devices re-sync configuration + menu dataDeletion Guard
Delete profile request
│
▼
getDeviceCount() for this profile
│
> 0 │ == 0
▼ │
abort(400)│ delete profile
"Profile │ (+ activity log)
is still │
used by │
devices" │Relations
Depends On
- Locations: A profile is created for a specific location; default menu and schedule fall back to location settings.
- Menus: Default and extra menus are served via the profile.
Affects
- Kiosk: Devices assigned to the profile take their menus and settings from it.
Related Features
Examples
Standard Kiosk Profile (custom default menu, both numbers)
json
{
"name": "Standard Kiosk",
"location_id": "loc-123",
"dining_option_1": "For Here",
"dining_option_2": "Takeout",
"use_custom_pictures_for_dining_options": false,
"custom_default_menu": true,
"default_menu_id": "menu-main",
"extra_menu_ids": [],
"idle_timeout_type": "standard",
"idle_screensaver": { "enabled": false },
"menu_item_columns": 2,
"order_number_display": "both",
"schedule_type": "Default",
"receipt_options": { "print": true, "email": true, "phone": false },
"auto_print_receipt": false
}Fast Food Profile (custom idle, 3 columns)
json
{
"name": "Fast Food",
"location_id": "loc-123",
"dining_option_1": "For Here",
"dining_option_2": "Takeout",
"idle_timeout_type": "custom",
"idle_timeout_seconds": 60,
"show_warning_for_seconds": 15,
"idle_screensaver": { "enabled": false },
"menu_item_columns": 3,
"order_number_display": "both",
"sell_without_stock": false,
"schedule_type": "Default"
}Takeout-Only Profile (one slot set to None)
json
{
"name": "Takeout Only",
"location_id": "loc-123",
"dining_option_1": "Takeout",
"dining_option_2": "None",
"idle_timeout_type": "standard",
"idle_screensaver": { "enabled": false },
"menu_item_columns": 2,
"order_number_display": "queue_number",
"schedule_type": "Default"
}Cafe Profile (screensaver + customer identification)
json
{
"name": "Cafe Kiosk",
"location_id": "loc-123",
"dining_option_1": "For Here",
"dining_option_2": "Takeout",
"idle_timeout_type": "standard",
"idle_screensaver": { "enabled": true, "minutes": 5 },
"menu_item_columns": 2,
"order_number_display": "order_number",
"allow_customer_identification": true,
"customer_identification_methods": { "member_code": true, "email": false, "phone": false },
"schedule_type": "Custom"
}FAQs
- "Can I create a KDS or POS profile here?" For POS, a flat no — no POS profile family exists in this surface at all. For KDS, in practice still no, but for a different reason than it used to be: a Kitchen Display family does exist in the New Device Profile dialog, but it is shown only to merchants running the first-party Upvendo POS, and the
/back-office/kds-profilesAPI group is behind thefirst-party-posmiddleware (403 otherwise). So the answer is a gate, not a missing selector — the old wording ("the type is hardcoded to Kiosk and there is no type selector") is no longer accurate, since the selector is there and shows a single Kiosk option for everyone else. - "Why does filtering the profile list by 'Kitchen Display' show an error?" Because that filter value is offered to everyone but the endpoint behind it is not. If your account is not on the first-party Upvendo POS, picking Kitchen Display switches the table to the KDS profile API, which refuses the request with "This feature is only available to merchants using the first-party Upvendo POS." Clear the type filter to get the normal kiosk/printer list back. Nothing about your permissions or your data is wrong. (Verified:
upvendo-backoffice/src/views/device-profiles/DeviceProfiles.vuelines 131-135 and 154-161;routes/api/backoffice/kds-profiles.phpline 31.) - "What happens when I save a profile that has assigned devices?" A
ReloadMenuevent fires for the profile's location, so devices using it re-sync their configuration and menu data. - "Why can't I delete a profile?" Deletion is blocked while any device is still assigned to it. Reassign those devices to another profile first.
- "Can different kiosks show different menus or settings?" Yes. Assign them to different profiles — each profile carries its own menus, dining options, idle behaviour, schedule, and more.
- "What's the difference between Idle Timeout and the Idle Screensaver?" The timeout ends an in-progress session and clears entered data after inactivity; the screensaver shows a custom image on an untouched kiosk after a set number of minutes. They are configured separately in Idle Settings.
- "What are the schedule types?" Default follows the location's hours, Custom uses per-day time ranges, and Deactivated turns scheduling off.
Troubleshooting
- Cannot delete profile → A device is still assigned (
getDeviceCount() > 0). Reassign those devices to a different profile, then delete. - "The dining options is invalid" →
dining_option_1anddining_option_2are set to the same value. They must differ. - Screensaver won't save → When the idle screensaver is enabled, both the minutes value and an uploaded image are required.
- Custom idle timeout rejected → In Custom mode, both "give warning after" and "show warning for" must be at least 1 second.
- Sell Without Stock toggle missing → It only appears when the location has tracked inventory.
- Menu not appearing on the kiosk → If the profile uses a custom default menu, confirm
default_menu_idis set; otherwise the location's in-house default menu is used. (Kiosk-app rendering: not-verified-here.) - "This feature is only available to merchants using the first-party Upvendo POS" on the profile list → The type filter is set to Kitchen Display, which reads from a first-party-only API. Clear the filter. The Kitchen Display option is offered to every merchant even though the data behind it is not. (Verified:
upvendo-backoffice/src/views/device-profiles/DeviceProfiles.vuelines 131-135;routes/api/backoffice/kds-profiles.phpline 31.) - No Kitchen Display option in the New Device Profile dialog → Expected unless the merchant runs the first-party Upvendo POS; the family is added to the selector only when that check passes, so a single Kiosk option is the normal view. It is not a permission problem and cannot be enabled from the back office. (Verified:
NewDeviceProfileDialog.vuelines 43-48;config/pos-providers.phpline 49 keeps theupvendoprovider unselectable.) - "You need the 'View Device Profile' permission to assign a Kitchen Display profile" → Usually literal: grant VIEW_DEVICE_PROFILE to the role. But a non-first-party merchant with a grandfathered Kitchen Display sees the same message, because the back office reports every 403 from the KDS options endpoint as a permission problem while the real refusal is the first-party gate. In that case the permission is not the barrier. (Verified:
src/store/modules/kdsProfile.tslines 151-154; message atsrc/plugins/i18n/locales/modules/en/devices.tsline 49; gate atroutes/api/backoffice/kds-profiles.phpline 31.)