Esper Features

The Cutover Window: Why Fleet-Wide Commands Matter Most During an x86-to-Android Migration

How Esper's Dispatch architecture replaces one-request-per-device commands with batched, scalable operations, and why that matters most in the six weeks when your old and new fleets are running side by side.

Kailana Kahawaii

August 24, 2026

Picture this: You’re three weeks into a high-stakes cutover at a QSR chain. Outside, 4,000 legacy x86 terminals are coming out; inside, 4,000 new Android units are going in, store by store. For six intense weeks, both fleets exist side-by-side. Configs drift between them constantly, and if a single command drops, a cash register at store #212 boots up Monday morning with last week's pricing rules.

This is the exact scenario where a one-request-per-device commands model stops working, not because it's slow, but because it's the wrong abstraction. You don't want to manage 4,000 individual devices during a migration. You want to describe the fleet segment that's mid-cutover and converge it in one motion. That's what Dispatch is built for.

Why does the request-per-device pattern fail at migration scale?

The original commands framework (what you may know as the Commands API) is built around a static list: you pre-fetch device IDs or point at a single group, then fire one request per device, executed immediately. 

That's a reasonable model when your fleet is homogeneous and stable. But it's the wrong model when 4,000 devices are actively changing state, some still on the old hardware, some freshly enrolled, some mid-provisioning.

Dispatch (what you'll see referenced as "Operations" in the API docs) inverts the model. Instead of a static list assembled by hand, you describe the fleet segment you care about, and the platform resolves the target set at dispatch time. During a migration, that segment isn't fixed, it's a moving target, which is exactly why query-based targeting instead of list-based targeting is the architectural requirement, not a “nice-to-have”.

Query-based targeting: Expressing the migration state directly

The Commands API accepts only a fixed device list or a single group ID, which means you have to pre-fetch and assemble your target list yourself before you can even send the request. Operations flips that around with operation_device_query. Instead of handing over a static list, you describe the devices you want using any of the filters already supported by the Device List API: platform, OS version, blueprint state, battery level, group membership, and more.

For the QSR migration, this is the most important query: converge every newly-provisioned Android terminal onto the correct payment-compliance blueprint, all without touching a single one of the legacy x86 units still finishing their last week in service.

Target only Android 11 devices currently on blueprint X:

{
  "operation_device_query": {
    "device_request": {
      "os": "android",
      "android_version": "11",
      "current_blueprint_id": "<blueprint-id>"
    }
  }
}

The same pattern generalizes cleanly. Target only GMS-certified Android devices in a group when you're staging a rollout to a specific region:

{
  "operation_device_query": {
    "device_request": {
      "group_multi": "<group-id>",
      "os": "android",
      "is_gms": "true"
    }
  }
}

You can also target devices last seen within the past 30 minutes with battery at 50% or higher for when you need to guarantee a push lands on devices that are actually online and won't die mid-update:

{
  "operation_device_query": {
    "device_request": {
      "os": "android",
      "last_seen_gt": "2026-07-24T09:30:00Z",
      "battery_level_gte": "50"
    }
  }
}

In every case, the query is the migration state expressed directly. No pagination, no pre-fetching device IDs, no reconciling which store is on which phase of the cutover by hand. 

For the full request schema and all supported query parameters, see the Create Operation API reference.

Reliability and operational controls

Customers running similar migrations have converged tens of thousands of devices — new configs, new app installs — in as little as three hours. A six-week phased cutover doesn't need six weeks of manual coordination; it needs one query re-run at each phase boundary.

To make tracking effortless, every Dispatch operation shows up in the Activity Feed as a single org-level job. Migration leads can easily follow cutover progress store by store, without having to piece things together from individual device logs.

And because migrations are exactly when someone pushes the wrong blueprint to the wrong segment, queued operations can be cancelled mid-flight, gated by a dedicated Cancel Commands permission that keeps that power in the hands of whoever owns the cutover.

That’s why query-based targeting isn't just a convenient feature for migrations — It’s the difference between a chaotic, spreadsheet-contained rollout and a smooth, software-coordinated deployment.

Why it matters most at cutover

Hardware migrations are usually where request-per-device architectures hit a wall because the fleet itself is intentionally unstable during the cutover. Query-based targeting provides dynamic control that turns a chaotic, spreadsheet-contained rollout into one that’s smooth and coordinated in software.

If you're currently migrating away from legacy x86 hardware or planning to, you can use the same operation_device_query pattern that targets a blueprint state or an OS version to target a migration phase. Reach out to your Esper representative to start mapping your cutover plan to a Dispatch query, or check out the Create Operation API reference to explore all available filters.

Learn More

Keep Exploring

No items found.

Learn More

Kailana Kahawaii

Kailana Kahawaii is a Senior Technical Writer at Esper. Before getting into tech, she was an educator. She has a passion for enhancing products that wow and inspire.

7 min read