When to call the API, and when you can skip it
A cross-border e-commerce team had an “order exception” alert in the support system. When a problem order showed up, someone had to reopen that order in the phone app and submit it again. The alert came from a system. The phone action still needed a person. One alert in the middle of the night meant someone getting up to tap once. They wanted the support system to do the tap.
The console does not know when the work is due. The alert system does. Once device actions are HTTP calls, any program that can send a request can drive the phone.
A fixed script on a schedule is a job for the console’s own scheduled task. The API fits a few other cases: the trigger lives outside the console, so an order system, an alert system, or your back end knows when to do what; you want to set the schedule and the retries yourself, without the console scheduler; the result has to be written back into your database, and the console execution history is not enough. If the console can already decide when to do what, there is no need to add an API layer.
There is no SDK for this, and you do not need one. It is an ordinary HTTP call. The address is the computer running the console, plus port 8019. A call on that machine is http://127.0.0.1:8019. A call from another machine uses that computer’s LAN IP. The method is HTTP POST, Content-Type: application/json, with parameters in the body. The response is JSON. code of 0 means success. Any other value means failure, and the reason is in msg. Wrap that convention first:
import requests
BASE = "http://127.0.0.1:8019"
def openapi_post(path, body=None):
r = requests.post(f"{BASE}{path}", json=body or {}, timeout=30)
r.raise_for_status()
data = r.json()
if data.get("code") != 0:
raise RuntimeError(data.get("msg") or data)
return data
Every later call goes through this function. Python depends only on requests. Node.js 18+ includes fetch, so there is nothing to install.
From deviceId to USB HID, then to MCP
Every device API needs a deviceId, so the first step is always the device list:
devices = openapi_post("/openapi/deviceList", {"deviceId": "", "groupId": ""})
print(devices)
An empty deviceId means do not filter by device. An empty groupId means do not filter by group. To take one group, fill in groupId. The alias is the name you set in the console for people to read. API calls use the deviceId returned in the list.
The second step is USB HID, and the tap comes last. The order is open the session, set the resolution, then tap:
DEVICE_ID = "90e2f3834c0977205e441aa664916a9bdde81e8d" # taken from the device list
# 1) Open the session
openapi_post("/openapi/usbhidSessionStart", {"deviceId": DEVICE_ID, "gate": True})
# 2) Set the screen resolution (coordinate conversion depends on it)
openapi_post("/openapi/usbhidSetScreenSize", {"deviceId": DEVICE_ID, "w": 1170, "h": 2532})
# 3) Only then can you tap
openapi_post("/openapi/usbhidClickPoint", {"deviceId": DEVICE_ID, "x": 200, "y": 400})
The USB HID open API matches EC iOS USB 10.7.0 and later (released 2026-09-08). It does not need a Bluetooth board or an OTG board. The phone should be on iOS 17 or later. It is mutually exclusive with the proxy automation service. Do not mix “Start Automation” in the console, or startEnv in a script, with this group of APIs on the same device. When you need the picture, use the no-automation screenshot API.
gate means whether to try enhanced compatibility mode. Older system versions ignore it. Pass true in the usual case. If a session already exists, it is reused. Screen size is the step people skip, and then every tap lands off. HID sends absolute pixel coordinates. w and h have to match the resolution you see in mirroring and screenshots. x and y are pixel coordinates. Devices with different resolutions need separate math. Once the session is open and the size is right, later taps only repeat step three. Opening a session may internally unmount and remount a newer developer image, after which startEnv may fail to start. On EC iOS USB 10.8.0 and later you can unmount the image and mount it again. In a script that is utils.unmountDevImage() and utils.mountDevImage(). Over HTTP it is /openapi/unmountDevImage and /openapi/mountDevImage.
The Node.js version has the same structure, with fetch in place of the Python call:
const BASE = "http://127.0.0.1:8019";
async function openapiPost(path, body = {}) {
const res = await fetch(`${BASE}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const data = await res.json();
if (data.code !== 0) {
throw new Error(data.msg || JSON.stringify(data));
}
return data;
}
The APIs are split into eleven groups. This table is faster than paging through the docs:
| Module | What it covers |
|---|---|
| Console API | Device list, script start and stop, and similar |
| Automation · actions | Tap, swipe, input, open and close apps |
| Automation · screenshots | Screenshots, image stream |
| Automation · start and stop | Start / release automation, tunnel, battery |
| Automation · photo library | Upload images and video, clear the library |
| Automation · files | Push and pull device files |
| Automation · IME | Custom input method, clipboard forwarding |
| Automation · Bluetooth BLE | HID actions on a Bluetooth board |
| Automation · USB HID | No extra hardware, a data cable controls the phone directly |
| Helper assistant | Assistant clipboard, photo library, port forwarding |
| Shortcuts assistant | Used together with the Shortcuts assistant program |
The action group is the one used most often. It covers tap, double-tap, long-press, swipe, multi-touch, text input, a simulated keyboard, open or close, install or uninstall an app, Home, reboot, lock and unlock, set screen orientation, correct the coordinate system, and capture nodes. The USB HID group does not need a Bluetooth board or an OTG board. A data cable can simulate taps and input.
When you manage a batch of devices, call the device list first to get each deviceId, then start the script on each one. The API is per deviceId. The loop lives in your code. Set the groups in the console first, so the loop has a clear source.
When an AI assistant needs to pick tools itself, register the APIs as MCP. Fixed steps call the API directly. Steps that need a judgment on the spot go to MCP.
Failures fall into two kinds. The console is closed, or the port is unreachable: those can be retried. The device is offline, the license has expired, or the coordinates are out of range: a retry does nothing useful, so read msg. The official examples use a 30-second timeout. Action APIs usually return in a few hundred milliseconds. Screenshots and uploads need a wider timeout, set per API. When models are mixed, do not hard-code coordinates. Convert by resolution, or capture the node and then tap. Log the device ID, the API, the request parameters, the returned code and msg, and a timestamp. Leave the flow in the script on the device. The API triggers it and collects the result.
Four kinds of need cover most cases, and they can sit on the same set of devices:
| Your need | Recommended path | Why |
|---|---|---|
| Run a fixed flow on a schedule | EasyClick console scheduled tasks | No extra API layer. The console can decide when to run. |
| An external system decides when to trigger | EasyClick open API, called directly | Port 8019, HTTP plus JSON, connected to the system you already have. |
| Let AI decide the next step | Register EasyClick as MCP tools | The AI picks the tool and fills the parameters. You do not write the scheduling logic. |
| Precise control of UI elements, and a full flow running on the device | EasyClick proxy mode with a script, and the API only as the trigger | The flow stays on the device, with fewer network round trips and fewer places to fail. |
These four paths use the same console and the same device licenses. Fixed flows use the scheduler. External triggers use the API. Steps that need a judgment go to MCP. Actions on the device are carried by the script.
8019 is a port on the computer running the console. Anything that can reach that computer can call it. Across networks you can use a tunnel, or cloud control. The docs match cloud control 3.11.0 and later, and EC client 9.4.0 and later. On the demo site http://ecloud.devicefarm.cn/ the username and password are both test123. The demo site cannot create, delete, update, or query. For many devices, loop in code or send at the same time with a thread pool. One device runs only one task at a time. Running a script uses the USB device license. Screen mirroring uses the USB mirroring license. You can check license status before starting. When code is not 0, check whether the device is offline, unauthorized, or has no session open, then match the API name in the docs for parameters and the return value.
After the alert system detects a problem order, call the device list, find the matching machine, run the script that resubmits the order, and write the result back to the ticket table.
To see how the script itself is written, read How to write an iOS no-jailbreak script. For the USB HID mechanism and the full API, see Apple cluster control, unpacked: USB HID principles and the full API tutorial. For connecting the API to an AI system, read Cloud control open API and MCP integration.
About EasyClick: A mobile automation script development platform covering three phone ecosystems: Android without root, iOS without jailbreak, and HarmonyOS. It also offers Apple script writing, Apple cluster control, Android cluster control, remote cloud control, and AI phone cluster control. → Explore all products
Ready to build it for real?
Every approach in this article can be built on the EasyClick phone automation platform — full documentation, developer tools and cluster/cloud-control products, free to try.