Skip to content

SUNMI DMP runbook — how to actually do things in the console ​

Task-oriented companion to sunmi-device-provisioning.md. That file is the narrative of what we learned and why; this file is the "I need to do X, how?" reference. If you are about to click around partner.sunmi.com, read this first.

  • Console: https://partner.sunmi.com · account Upvendo [Master] · entity Upvendo Benelux BV
  • Entity(Account) ID: 2YDNJA8U3KH4O (Upvendo Benelux, read from the top-right profile popover 2026-09-28). Hardware lives here, not in Upvendo, Inc. (VIIF3M32AS2VX, zero devices — an earlier version of this page gave that ID for the hardware account, which was wrong). A SUNMI user account belongs to exactly one entity — see Accounts, entities and the one-way doors.

Purpose ​

How to operate SUNMI devices in the SUNMI Partner/DMP console: provisioning profiles, device groups, remote support licensing, and the console behaviours that silently lose work. Use this when administering Upvendo's SUNMI kiosks (FLEX 3) and POS tills (D3 PRO).

Console traps — read before you click ​

These cost hours each. They are properties of the console, not of our setup.

TrapWhat happensWhat to do
Stacked dialogsA dialog that "failed" often did not close. A second attempt opens a second dialog on top, and a plain OK selector hits the stale one underneath — silently doing nothing, with no errorAlways target the topmost dialog. In Playwright: [role=dialog]:visible button.partner-devices-btn-primary then .last(). Reload the page to clear stale dialogs before retrying
Optimistic UIA tree/table can show your change immediately even when the server rejected it. A "verified" read taken before a refresh can be fictionVerify after a page reload, always. A group we created and confirmed at depth-32 had silently not persisted
Greyed ≠ unsupported, and ≠ unlicensedA greyed item may be (a) the device is offline — on an offline FLEX 3, Reboot/Power Off/Remote ADB/Get Log/Send Files all grey out together; or (b) that one capability is gated server-side. Neither is "the hardware can't"Compare the same menu on an ONLINE device. If exactly one item is grey there, it is that capability, not connectivity or the package
Group names are globally unique across all of SUNMIA common name fails with code 13010129 channel name repeat, visible only in the network response — the UI may just not saveAlways prefix: Upvendo BNL <thing>
Read the count, not the tableThe group Profile tab's Version column shows the version at bind time, not the live one. The header Bound profiles in this group(N) is the reliable readoutAfter binding, confirm N incremented and the new row shows Source = This Group
CAPTCHA gating is unevenPublishing a profile hits a high-risk CAPTCHA; binding an existing profile to a device does notExpect a human for publishes; binds can be done unattended

Remote Control — working, and how to provision it ​

Remote Control is live (RM drove DP02261212845 on 2026-09-22). Two server fields are involved and they are not the same thing — conflating them was the day's last mistake:

FieldWhat it meansHow it changes
can_controlthe console's Remote Control action is clickable at alllatches true and stays true
unattended_switchwhether the merchant must tap Accept on the device per sessionfollows the on-device toggle, both ways

Measured on DP02261212845, with DP02261811229 as an untouched control:

start           unattended 0   can_control false   (greyed)     | control: 0 / false
toggle ON       unattended 1   can_control true    (clickable)  | control: 0 / false
toggle OFF      unattended 0   can_control TRUE    <-- latched  | control: 0 / false

So turning unattended back off does not take Remote Control away. An earlier draft of this page said unattended_switch gates can_control. It does not.

What latches can_control — answered: throwing the Unattend toggle once ​

The earlier hypothesis — "the Remote Assistance app has been launched at least once" — is DISPROVEN. On DP02261811229, Get Log opened a live file browser of the device's storage, which only com.sunmi.remotecontrol.pro can serve: the app is running and answering MDM requests. can_control was still false immediately afterwards.

The only action ever taken on the working device and never on the control device is turning Unattend ON. That is the latch:

  • Unattend ON, once → server sets can_control: true, permanently.
  • Unattend OFF afterwards → only the per-session Accept prompt comes back; can_control stays.

Consequence: there is no remote or central way to do the first one. It is one physical (or adb) touch per device, before that device leaves your hands.

Not yet tested: whether a Remote Control session actually works in attended mode (unattended OFF, can_control true, merchant taps Accept). Worth 2 minutes on DP02261212845 — if it does, staffed tills can run with the prompt on, which is the better posture.

Setting unattended ​

bash
tools/sunmi-unattended.sh status          # read it
tools/sunmi-unattended.sh on              # set it
tools/sunmi-unattended.sh on -s <serial>  # pick a device

Opens the app over adb — this works through Kiosk Mode, because am start is not blocked by LOCKED_SUNMI, so a locked-down till needs no PIN exit. Exits 1 unless it ends in the requested state.

By hand, where adb is not available: exit Kiosk Mode (POS: power → Exit Kiosk → PIN. Kiosk app: 5 taps → PIN 111111) → open Remote Assistance (orange icon, two arrows in a circle) → tap Unattend so it turns orange → wait 3–5 s for it to stay on → Home.

Traps ​

  • checked= lies. mainScreenUnattendedSwitch is a custom android.view.View, not a Switch, so uiautomator reports checked="false" while the toggle is visibly orange. Read the rendered pixel: ON ≈ rgb(255,96,0), OFF ≈ rgb(164,166,170). The script does.
  • It reverts on a weak connection. Always re-read after setting.
  • Nothing in Android settings tracks it. A full settings list global/secure/system diff across an on→off toggle showed zero differences, so there is no settings put shortcut.

There is no central switch — checked, not assumed ​

  • DMP Profile: the full catalogue is Wallpaper / Boot Animation / Launcher · Kiosk Mode / Default Startup · WLAN / Access Control / mDNS · Notification / App Lock / Settings / Super Permissions / Component Control · Printer / Scanner / Subscreen · Time Zone / Languages / Keyboard / Security / Display / Sound and Vibration / NFC / Battery / Physical Key. Nothing remote-assistance related. (Do not disable com.sunmi.remotecontrol.pro via Component Control — that removes the capability outright.)
  • DMP commands enabled on this account (.../mdm/partner/account/enableCommand): download, upload, clearKeyGuard, lockDevice, openRemoteADB, timingSwitch, launcher, apn, appAuthControl, remoteControl, remoteUnlockDevice, shutdown, reboot, uninstall, sendMessage, settingManage, timingSleep, securityConfig. No unattended command, and no remoteScript.
  • Open API: SUNMI advertises ~82 DMP open APIs and the family is real (/v2/mdm/open/open/device/applyControl starts a control session), but the public developer docs for Sunmi Remote 404. Worth one question to SUNMI: is there an API to set unattended, and can it be set at provisioning time? Ask alongside the Remote ADB question below.

The remaining gap: devices already at a merchant ​

For anything we hold before it ships, tools/sunmi-unattended.sh on is the provisioning step and costs seconds. Put it in the bench checklist — it is the one step that cannot be done later from a desk.

For a unit already in the field there is no remote path today. Two things would change that:

  1. Remote ADB working — the script would then run remotely and close the loop entirely. It currently fails "System version is too low" on ROM 4.0.79 and is believed to need an OS upgrade wave (Device → Device Upgrade), not yet attempted. This makes the upgrade wave worth more than it looked: it is the difference between a site visit and a script.
  2. A SUNMI Open API endpoint — unconfirmed; see below.

Last-resort avenue, not attempted and not recommended without a spare unit: Get Log's file browser is served by the privileged system app, so it may be able to read /data/data/com.sunmi.remotecontrol.pro/shared_prefs/, which Send Files could in principle write back. Editing a system app's private state this way risks breaking the agent on a live till. Try it on a bench unit or not at all.

What Get Log and Send Files actually are — more useful than the names suggest ​

Get Log opens a live, browsable file tree of the device (sdcard + data/public, with a size budget), and Send Files pushes files to it. Both work on an online device with no unattended and no Remote Control. That is a real support capability we were not using: pull a log off a merchant's till without a visit.

OS upgrades — we cannot push one, and 4.0.102 is not offered to us ​

Attempted 2026-09-22, blocked at both ends. The OS List is a catalogue, not an availability statement.

  • Catalogue: 4.0.102 (code 1318, built 2026-09-22, security patch 2026-09-05), Supported Models: D3_PRO_E_GL — exactly our D3s, which run 4.0.79 (4.0.79_1011). Release note: "1. Supported accessibility permission configuration 2. Supported button configuration 3. Updated security patches. Components: 1. Supported hiding hotseat in Navigation Bar." "Button configuration" is very likely the Physical Keys support that ROM 4.0.23/4.0.79 ignore. 4.0.87 also carries "Fixed USB external device issues".
  • Console cannot push it. Device → Upgrade Mode reads Public Follow Mode: "Manufacturer-led… End users choose whether to upgrade… Partner customers do not need to manage upgrades." Consistent with Upgrade Management listing only the 10 un-activated FLEX 3s — neither D3 and not the activated FLEX 3 appear there at all.
  • The device is not offered it either. com.sunmi.ota → System Update on DP02261212845, after an explicit Check for updates: "SUNMI OS 4.0.79 / 1011 — Already the latest version."

So in Public Follow Mode SUNMI's own release strategy gates which units see which build, and ours are not in the 4.0.102 wave. Nothing to do on any device right now — which also makes the "upgrade the offsite unit first" risk moot.

Three ways forward, in order of cost:

  1. Wait — 4.0.102 was built the same day; a staged rollout may reach us.
  2. Ask SUNMI to release it to our SNs, or explain which channel/region gate applies. Bundle this with the Remote ADB and unattended-API questions — one ticket, three asks.
  3. Switch the account to Self-OTA Mode (Device → Upgrade Mode → Switch to Self-OTA Mode). We would then choose versions per device and could push 4.0.102. ⚠ Account-wide: it changes upgrade control for every device including future merchant units.

Decided 2026-09-22 (RM): we move to Self-OTA. In Public Follow Mode "end users choose whether to upgrade" — any merchant can pull an untested ROM onto a live till. Self-OTA gives us version choice per group, staged rollout (Grayscale), and the per-device Night Upgrade / Auto download / Speed Limit settings shown in Upgrade Management, so a ROM never lands during opening hours. Each ROM is bench-tested on one D3 + one FLEX 3 first (Kiosk Mode, bars hidden, auto-start, USB print, can_control, Physical Keys), then Internal, then merchants.

Switched 2026-09-22 (RM, by hand). Upgrade Mode now reads Self-OTA Mode: "Partner-led… The upgrade pace is fully controlled by the user." It is reversible (a Switch to Public Follow Mode button sits next to it). New menu items: Task List and OTA Setting. The built-in 6-step tour, summarised:

  1. Configure policies first — device-add approval and version approval, in OTA Setting, before creating any task.
  2. Device Addition Approval — adding ≥ threshold devices to a task in one go (default 50, range 10–10000) needs an approver's sign-off before they join the queue.
  3. Version Approval Workflow (toggle, off by default) — when on, every OS List version must be approved before anyone can push it.
  4. OS List — browse versions per model, read release notes.
  5. Create Upgrade Task — only from approved versions (when approval is on).
  6. Task List — monitor execution; filter pending approval for batches awaiting review.

⚠ The Task List the tour shows (P3_MIX_STD 3.0.67, tasks named 12312312312) is demo data — it vanishes when the tour closes; our real list is empty. Its schedule columns read GMT+08:00, so check which timezone a real task's start/end window is interpreted in before relying on it to avoid opening hours.

Configured 2026-09-22 (verified after reload): Device Addition threshold 10 (the minimum), approver admin@upvendo.be; Version Approval ON, version approver admin@upvendo.be. Only admin@upvendo.be and keanu@upvendo.com are selectable users on the account.

How to push a ROM (the "Create Upgrade Task" button is NOT on the Task List — it is inside the version's dialog):

  1. OS List → pick the model (e.g. D3_PRO_E_GL) → row Approval → confirm ("Once approved, all users with upgrade permissions can push this version"). Reload: the row reads Approved and its button becomes Revoke Approval.
  2. Same row → Detail → Create Upgrade Task. Task name, remarks (50-char cap), Time Zone (defaults to Europe/Brussels — the GMT+08:00 in the tour was demo data), Start Immediately + End Time (a 7D preset exists). Defaults worth keeping: Auto Install with upgrade window 02:00–06:00, no download over mobile data, 200 KB/s download cap (1.77 GB ≈ 2.5 h), power-on upgrade prompt.
  3. Add SN → paste SNs one per line → Submit (each row must read OK) → OK → Preview → Create. Task appears on Task List as Running.

First task: D3 4.0.102 pilot - Keanu DP02261811229 — 4.0.102 (1318) → DP02261811229, created 2026-09-22 23:08 Brussels, window until 2026-09-29 23:59, installs only 02:00–06:00. His till must be powered and online overnight. Edited 23:16 at RM's request to install tonight: upgrade window 23:00–23:59, download speed limit off ("Use the device's speed limit"). Task configuration is editable after creation (Task Detail → Task Configuration → Edit). ⚠ The window picker rejects windows that cross midnight (23:00–06:00 is marked invalid), so a night window must sit inside one calendar day, e.g. 00:00–06:00. Restore 02:00–06:00 as the default for merchant tasks.

Result at 00:00 (2026-09-23): the till never picked the task up. Still Queued on 4.0.79, Update Time unchanged since creation, Status Detail -- — even though the same device answered a live Get Log a few hours earlier. So creating a task does not reach the device immediately; it waits for the device's OTA client to check in, and that trigger is not yet known (periodic poll, boot — note the Power-On Upgrade Prompt option — or a manual System Update → Check for updates). Window moved to 00:00–06:00 for a second try overnight. Until the trigger is measured, do not count on a task landing on a given night — which matters for any merchant rollout plan.

The check-in trigger, measured on DP02261212845 (2026-09-23). The device-side client is com.sunmi.ota. It schedules an RTC_WAKEUP alarm com.sunmi.ota.regular_check; right after the app starts, the next one was set 12 h out (08:05 → 20:05). Its receivers also fire on BOOT_COMPLETED, CONNECTIVITY_CHANGE, ACTION_POWER_CONNECTED, and named schedules (thirty_minute, four_pm, twentyThree_thirty, one_day). Opening System Update → Check for updates checks immediately. So a newly created task reaches a device at its next check — up to ~12 h later — unless it reboots, changes network, or someone taps Check for updates. With Auto Install on, it then downloads and waits for the next upgrade window. Practical rule: create tasks at least a day before the window you want them to land in. Still to confirm on a device that is in a task: that a manual Check for updates actually picks the task up.

⛔ Never am force-stop com.sunmi.ota. Force-stop cancels all of its alarms and leaves the app in the stopped state, so it stops checking for updates entirely until it is launched again. Measured: I force-stopped it at 22:00 to close the updater screen and the D3 had no pending check for 10 h, until relaunching it rescheduled regular_check. To leave the updater screen, press Home or relaunch the till app instead. (Same trap class as com.sunmi.remotecontrol.pro, except that one relaunches itself; this one does not.)

Second console reboot, same outcome (2026-09-23 08:17). Rebooted DP02261811229 (off-site, at Keanu's) to trigger the OTA boot check. Task Mgmt: Reboot_20260923_953825 Completed 1/1 — but ~9 min later is_online: 0 and the menu shows the offline pattern (Get Log / Reboot / Power Off / Remote ADB / Send Files greyed). Completed means the device acknowledged the command, not that it came back. That is now two for two on D3s. Treat a console reboot of an off-site unit as a possible site visit. Before the reboot the OTA task was still Queued; it stayed Queued.

What the device's own update check returns (read from com.sunmi.ota logcat on the reachable D3): RemoteConfigEntity(openLocalUpgrade=1, checkInterval=43200, startHourMinute=02:00, endHourMinute=06:00) — the 12 h poll is server config, not a client default — and UpdateInfo(updateFlag=0, downloadUrl=, autoInstall=0, startHourMinute=, bootAugrade=0, …) for a device that is not in a task. A device in a task should get updateFlag=1 plus the URL and window.

The console's alive_time is also not a liveness signal — it read 09-22 00:58 for a D3 that had been up for 7 days and answered adb at that moment.

After it lands: confirm version_name 4.0.102 in the device list, then test Physical Keys (the "button configuration" note) and Remote ADB ("System version is too low" on 4.0.79).

GKS 2.0 does not name the OS/ROM (checked in gks-certification-pack/). The certified identity is the POS software — naam, model, versienummer van de software, DB version — plus the hardware types (handleiding §II.A/C/F). The only firmware the pack regulates is the FDM's. The broad line "Voor elke wijziging op de POS is een verzoek voor een certificeringsupdate nodig" (§II.E) and the addendum's "toute modification apportée à la solution certifiée" (ch. 2) leave a sliver of doubt; if we want it zero, it's one question to the GKS service. The same §II.E recommends secure remote access for updates and support (TeamViewer/AnyDesk-class, ideally without time limits) and asks how updates reach the test machine — controlled OTA + SUNMI Remote Control is a good answer to exactly that question.

Reminder of why this matters beyond Physical Keys: Remote ADB fails "System version is too low" on 4.0.79, and Remote ADB working is what would let tools/sunmi-unattended.sh run against a field unit instead of someone driving there. No release note promises that fix, so treat it as a hope, not a plan.

Security ​

Unattended means any operator on our DMP account can open that screen at any time with no prompt on the device. Correct for an unmanned kiosk; a real exposure on a staffed till, where leaving it OFF still gives us Remote Control with the merchant tapping Accept. Decide per device type, and put it in the merchant support agreement.

Two causes previously recorded here were WRONG — kept, the pattern is the lesson ​

  • ❌ "GMS certification removes screen mirroring." From a SUNMI marketing blog. The ROM ships /system_ext/priv-app/SunmiRemoteControl_v4.3.5_gms_release as a PRIVILEGED system app with CAPTURE_VIDEO_OUTPUT + CAPTURE_SECURE_VIDEO_OUTPUT: granted=true.
  • ❌ "We own zero licences — License Management reads Unbind: 0/0." From a field label. Unbind is the unbind quota (total_unbind/used_unbind); the account holds total_license: -1 (unlimited), used_license: 0.

Both were adopted explanations recorded as measurements, for one unchanged observation — the button is grey. Either would have died in five minutes by opening the app on the device and looking.

The licence, separately ​

POST /public/v1/mdm/partner/account/dashboard: Premium Edition (id 94), 2026-09-04 → 2026-10-05 15:59 UTC, has_renew: 0, total_license: -1, total_time_len: -1 (unlimited remote-control minutes), used_rmtctrl: 0, spend USD $0.01. A trial that lapses in October, dropping us to Free Edition (30 remote-control minutes/month). Now that Remote Control works, exercise it before 2026-10-05 and decide whether 30 min/month is enough.

Reboot works but is not free. It once released a stuck print-bridge lease and left the till offline for 45+ minutes, needing someone on site. With Remote Control available, look at the screen before rebooting blind.

Groups ​

Structure as of 2026-09-28 (read back from getGroupList after a reload):

Upvendo Benelux                         268941  org
├─ Upvendo BNL Internal                 270642  org  ← binds: Upvendo BNL POS Baseline (Time zone Europe/Brussels)
│  ├─ Upvendo BNL Internal Kiosks       272781  device group ← binds: Upvendo BNL Kiosk V4.0 + inherits Baseline [FLEX 3]
│  └─ Upvendo BNL Internal POS          272782  device group ← binds: Upvendo BNL POS   V4.0 + inherits Baseline [D3 PRO]
├─ Upvendo BNL Merchants                270643  org
└─ Upvendo BNL Resellers                270644  org
   └─ Upvendo BNL Hendrickx NV          273315  device group ← production kiosk profile goes HERE (not yet created)
      ├─ Upvendo BNL Hendrickx Showroom 273316  device group   [F306P57XJ0057]
      └─ Upvendo BNL Meander            273317  device group   [F30625BJJ0442, F30625BJJ0057]

Organisations vs device groups. The four top nodes are organisations (group_category: 2, each with its own org id — created under System Management → User&Org). Everything below them is a device group (group_category: 1, created with the + in Device Group). getGroupList reports org_gorup_level_limit: 2 (sic) and device_group_level_limit: 12: organisations stop at two levels, so a reseller or merchant is a device group inside the Resellers / Merchants organisation, never a new organisation — and never a sub-account (see the one-way doors).

Bind type-specific profiles at the customer level, not at Resellers/Merchants. Anything bound to Upvendo BNL Resellers reaches every reseller's devices; the first D3 till a reseller sells would boot into the kiosk app. That is the same reason Internal is split into Kiosks/POS.

Provisioning is now one step: drop the device in the right group. Binding confirmation text: "The configuration will take effect immediately on devices in the group and apply automatically to any new devices added later." Before 2026-09-22 the two V4.0 profiles were bound per device, so the type groups looked right and provisioned nothing — group membership ≠ provisioning.

  • Create a child group: select the parent in the tree first, then click the + in the tree header. The dialog has only Group Name + Remarks — the parent comes from the selection.
  • Child groups INHERIT the parent's bound profile. Verified: an empty child showed the parent's Baseline with Source = the parent and Operation - (inherited, not unbindable there). So moving a device down a level does not drop config bound higher up.
  • Why split by device type: Upvendo BNL Internal is mixed-type. Group-binding a POS profile there would push POS Default Startup onto the kiosk. The Kiosks/POS children exist so each type's profile can be bound at group level without touching the other.
  • The parent keeps only what is type-neutral. Upvendo BNL POS Baseline is bound at Internal and carries time zone only, so kiosks inherit it harmlessly. Its name says "POS" and its contents do not — read the profile, not the name.
  • Merge priority: Device > Group > Smart Group. A per-device binding always wins over a group baseline, so the two can coexist safely.

Moving devices between groups ​

Group → Device tab → tick the device → Actions → Batch Move → pick the destination → OK.

  • Before OK, confirm the tick marker moves to your destination in the dialog tree. The marker starts on the device's current group.
  • OK opens a second dialog, "Move device … N units of devices will be moved!", stacked on top of the first. Check N, then confirm that dialog — the first stays open underneath until it does.
  • The dialog's group search filters the tree but keeps it collapsed — expand the parents with their arrows to reach a nested group.
  • The device-tab SN search takes one SN: a comma-separated list returned no rows (2026-09-28). Move units one at a time or tick them on the unfiltered list.
  • ⚠ Retracted 2026-09-22: "batch move fails silently" was never true. Both the 2-device batch and the single move returned {"code":1,"msg":"success"} and had moved the devices. What failed was the verification — it read a stale device list. Two hours were spent re-running a working operation. Never conclude "it silently failed" from a UI read.
  • Verify a move from the API, not the table. POST /public/v1/partner/device-manage/device/group/getGroupList returns sn_count per group (subtree total), and …/device/getGroupDevice returns each device's full group_name path. Those are the artefacts.
  • The move request carries no SN list. It posts {group_id, fingerprint, cid}, where the fingerprint comes from a prior …/task/generateSearchFingerprint call that did carry sn_list. So a move you cannot explain is diagnosable only by reading both requests.
  • The Organization column on the data-center list shows the org, not the group path, and it lags — it still read the old group after a confirmed move. Use the group's Device tab → Group Path column, or the API above.

Profiles ​

ProfileContentsBound to
Upvendo BNL Kiosk V4.0Kiosk Mode (locks com.upvendo.kiosk.dev, Active Recovery, Hide Status + Nav Bar), Default Startup, Physical Key, Super Permissionsgroup Internal/Kiosks (since 2026-09-22) + legacy per-device on the FLEX 3
Upvendo BNL POS V4.0Kiosk Mode (locks com.upvendo.pos.testing, Active Recovery, Hide Status + Nav Bar, exit PIN), Default Startupgroup Internal/POS (since 2026-09-22) + legacy per-device on both D3s
Upvendo BNL POS Baseline V1.0Time zone only (Europe/Brussels + Forbid User Modification) — the name lies, there is nothing POS-specific in itgroup Internal (everything inherits it)

⚠ The Kiosk profile V4.0 is missing two required settings (2026-09-29): Default Startup has Auto Recovery OFF (sunmi_watchdog_package empty on the FLEX 3, device rounds 2/3), and Super Permissions does not grant Alert Window. The FLEX 3 happens to have the overlay permission allowed on the device, so the device rounds passed. A fresh unit from this profile may not. Fix both before the production kiosk profile is copied from it — required kiosk DMP settings.

⚠ There is no production kiosk profile yet (2026-09-28). The only kiosk profile locks the dev build com.upvendo.kiosk.dev. The private App Store holds exactly three apps: com.upvendo.pos 1.0.0, com.upvendo.pos.testing 1.0.0, com.upvendo.kiosk.dev 1.0.206 (read from appstore-partners/public/app/getMyAppList). Merchant/reseller kiosks need, in order: a signed com.upvendo.kiosk production APK uploaded to the private store (App Store → Upload Apps → Private App Store) → a copy of the Kiosk profile pointing Kiosk Mode + Default Startup at com.upvendo.kiosk (deploy = CAPTCHA, human) → bound to the customer's device group. Do not bind the dev Kiosk profile to a customer group — it would lock their kiosks into the dev app.

The per-device bindings are now redundant with the group bindings and are the same profile, so they cannot conflict (Device > Group merge priority resolves to the same config). Leave them or clear them; do not clear them while the group binding is unverified.

  • Bind a profile to a GROUP (preferred): group → Profile tab → Bind Profile → tick the profile → Next → priority-sort screen → Save → Confirm Binding. No CAPTCHA. Verified working 2026-09-22 on both type groups. This is what makes a new device self-provision.
  • Bind a profile to a DEVICE: open the profile → Bound tab → Add Device → tick the SN → Next → Confirm Binding. No CAPTCHA. Applies when the device next checks in, so binding an offline device is fine. Use this only for one-offs — it does not scale and it hides intent.
  • Publish/deploy a profile: Edit → change items → Save Configuation per item → Deploy Profile → Continue → CAPTCHA (needs a human). Verify the version bumped (e.g. V3.0 → V4.0) and the item count changed.
  • Verify an item actually saved: the left-hand menu item must gain a check-circle. Kiosk Mode cannot be saved at all until an app sits in its lock table.

Fleet inventory (2026-09-28) ​

13 devices: 11 FLEX 3 + 2 D3 PRO (getGroupDeviceDetail on the root).

SNModelAliasGroupNotes
F30625AVJ1031FLEX 3FLEX 3 - Kiosk (Kragendijk 185)Internal/KiosksROM 4.0.23, offline since 2026-09-15; unattended OFF
DP02261212845D3 PROD3 Pro - Remy (POS testing)Internal/POSROM 4.0.79, GMS, online; unattended ON, can_control true — Remote Control PROVEN by RM
DP02261811229D3 PROD3 Pro - Keanu (POS testing)Internal/POSROM 4.0.102 (the 2026-09-22 upgrade task landed; console ROM column, 2026-09-28), offsite; unattended 0 / can_control false — needs Keanu to throw the toggle once. First device on 4.0.102: test Remote ADB and Physical Keys here
F306P57XJ0057FLEX 3—Resellers/Hendrickx NV/Hendrickx Showroom11th FLEX 3, different serial batch — not a typo of F30625BJJ0057 (both boxes physically present)
F30625BJJ0442, F30625BJJ0057FLEX 3 ×2—Resellers/Hendrickx NV/MeanderMerchant Meander, via reseller Hendrickx NV
F30625BJJ0273/0515/0591/0416/0104/0459/0443FLEX 3 ×7—unassignedNo group, no profile

⚠ Unassigned FLEX 3 units have no group and no profile — they will boot to the bare SUNMI launcher (no app auto-start, visible system bars, no USB grant) until provisioned. Bench checklist, both steps required:

  1. Move into the right group — Upvendo BNL Internal Kiosks for our own units (the Kiosk profile is bound there), or the customer's device group once its production profile is bound. The kiosk profile must carry the four required kiosk DMP settings: Default Startup with Auto Recovery ON, Super Permissions Alert Window for the kiosk app, Kiosk Mode lock table, and (recommended) Launcher = kiosk or Launcher3 disabled. Without the first two the kiosk cannot bring itself back after a crash or a WebView update. Once upvendo-kiosk #720 ships (not in current builds), the kiosk also says so in Slack once a day ("Kiosk is not fully provisioned").
  2. tools/sunmi-unattended.sh on -s <serial> — the only thing a Profile cannot do, and the only thing that needs the unit in your hands. Do it before it ships, or it becomes a site visit. Turning it back off afterwards is fine — can_control has already latched.

Getting a unit to the point where the script can reach it ​

Ethernet removes the network typing (measured on F30625AVJ1031: online in DMP with no WiFi typed), but the Android setup wizard still needs a human on every unit (language + a few confirmations). After it, the group's profile, app install and Kiosk Mode flow automatically. Whether the profile lands before the wizard finishes is not measured. The Upvendo activation code (which merchant the kiosk belongs to) is still typed on the device. For tools/sunmi-unattended.sh the unit additionally needs adb: finish the wizard, then enable Wireless debugging (or USB).

Hendrickx NV provisioning (in progress, 2026-09-28) ​

Reseller Hendrickx NV: 1 FLEX 3 for their showroom + 2 for merchant Meander. Boxes labelled.

StepState
Device groups created (Hendrickx NV → Showroom, Meander)✅ verified after reload
Units moved (see inventory)✅ verified per-device Group Path
Production kiosk APK in private store⏳ Production kiosk APK handed to RM by Faizal (2026-09-28); upload pending. Earlier candidate built from upvendo-kiosk origin/production cb5e9203 (1.0.206, versionCode 230, OTA channel production, signer CN=Upvendo Kiosk) — not uploaded. Open question: kiosk prod Firebase project (upvendo-kiosk in the local prod env vs upvendo-production used by KDS prod)
Production kiosk profile created + bound to Upvendo BNL Hendrickx NV⏳ after APK; deploy needs a CAPTCHA
tools/sunmi-unattended.sh on -s <serial> on all 3⏳ units on the bench; unattended stays ON (unmanned kiosks)
Upvendo activation per unit (showroom vs Meander)⏳

Group names carry the Upvendo BNL prefix only as a guard against SUNMI's global name uniqueness — not a requirement. Renaming is fine; check the response for 13010129 if you do.

Accounts, entities and the one-way doors ​

  • Two entities, both on the global node (partner.sunmi.com): Upvendo Benelux (2YDNJA8U3KH4O) holds all hardware; Upvendo, Inc. (VIIF3M32AS2VX) holds none. Supplier Duranmatic transfers devices into Benelux.
  • One user belongs to exactly one entity — inviting an address that belongs elsewhere fails with "The user has already joined another partner".
  • Adding a user: System Management → User&Org → root org → User tab → Add operator → email + Role + slider CAPTCHA (human) → send invitation. The row shows not actived until the invite is accepted. Users on 2026-09-28: admin@upvendo.be, keanu@upvendo.com, faizal@upvendo.com (SystemAdmin, invite accepted 2026-09-28) — plus the SuperAdmin owner.
  • ⛔ Cooperative (collaborative) sub-account = one-way door. Per SUNMI's help text, sub-accounts carry device ownership, "the parent account cannot manage the devices of the cooperative sub-account", and transferred devices "cannot be withdrawn". Never create one or transfer ownership to organise our own fleet or a reseller's — use a device group. Only if a reseller demands their own SUNMI console, and only with RM's explicit sign-off.
  • Regional clouds are separate account namespaces: partner.sunmi.com / partner.eu.sunmi.com / partner.us.sunmi.com; a session on one does not carry to another.
  • Entity-wide 2FA is set on account.sunmi.com/entity/profile?entity_id=<id> (System Setting in the console only links out); enabled for Benelux on 2026-09-04, Email or SMS.
  • App distribution is entity-scoped (from SUNMI's App Store Public and Private Pools manual, not measured): a Private App Store app is visible only to its own entity; reaching another entity's devices needs the Public store (manual review) with friend-channel visibility.

Known-not-possible / open ​

  • Physical Keys (power-button lockdown) is unsupported on D3 PRO (L3 / FLEX 3 only), and on FLEX 3 ROM 4.0.23 it deploys but is silently ignored — see the provisioning doc.
  • Remote ADB failed "System version is too low" on ROM 4.0.79. DP02261811229 is now on 4.0.102 — untested there.
  • Premium Edition lapses 2026-10-05, has_renew:0 → Free Edition, 30 remote-control min/month. Remote Control now works, so test whether that quota is enough before the date.