Lovely RouterДокументация
Получить ключ
Справочник API

Эндпоинты телефонов

Все эндпоинты /v1/phones для облачных телефонов, приложений, экрана в реальном времени, прямого управления и запусков агента — с параметрами, лимитами, ответами и ошибками.

API облачных телефонов находится по адресу https://lovelyrouter.com/v1/phones. Аутентифицируйте каждый запрос своим API-ключом в заголовке Authorization: Bearer $LOVELY_API_KEY (Аутентификация). Тела запросов передаются в JSON, кроме загрузки APK и скриншотов. Телефон стоит $1.20 за час активной работы, с поминутной оплатой с предоплаченного баланса; см. сколько стоит телефон.

Пошаговое описание смотрите в обзоре облачных телефонов. Координаты везде задаются в пикселях скриншота, короткая сторона которого — 540 пикселей: 540×1200 в вертикальном положении, 1200×540, когда телефон повёрнут горизонтально (игра, видео). Какой из вариантов сейчас, показывают width и height скриншота.

Объект телефона#

Атрибуты

idstring

ph_ и 20 символов.

objectstring

Всегда phone.

statusstring

starting (около минуты, дольше, пока устанавливаются стартовые приложения), ready, failed или deleted.

namestring | null

Ваша метка.

userstring | null

Id вашего конечного пользователя, если вы его задали.

metadataobject | null

Данные, которые вы сохранили вместе с телефоном.

startup_appsarray

По одной записи на каждое приложение из apps: source, status (pending, installed или failed), packages (имена установленных пакетов) и error.

created_atready_at

Время в секундах Unix.

deletes_after_idle_atinteger | null

Когда телефон будет удалён, если до этого им не воспользуются (через 1 час после последней активности).

awake_secondsinteger

Оплаченное на данный момент время активной работы.

charge_usdnumber

Сколько телефон стоил на данный момент.

end_reasonstring | null

Почему он был удалён: deleted (вами), idle, balance или failed.

errorstring | null

Почему он не запустился.

Создание телефона#

POST/v1/phones

Создаёт телефон и, пока он запускается, возвращает 201 с объектом телефона. Следите за ним через Получение телефона с wait. На балансе должно хватать на 15 минут работы телефона. У каждого аккаунта одновременно может быть 3 телефона.

Параметры тела запроса

appsarray of strings

До 20 приложений, которые нужно установить до перехода телефона в ready: ссылки https:// на файлы .apk, .apks или .xapk либо имена загруженных APK. Неудачная установка не приводит к сбою телефона; проверяйте startup_apps.

namestring

Метка, до 80 символов.

userstring

Id вашего конечного пользователя (до 200 символов), чтобы выводить его телефоны через GET /v1/phones?user=.

metadataobject

До 4 КБ ваших собственных данных.

waitinteger

Сколько секунд удерживать запрос, пока телефон не будет готов, до 50.

cURL
curl https://lovelyrouter.com/v1/phones \
  -H "Authorization: Bearer $LOVELY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"apps": ["https://f-droid.org/F-Droid.apk"], "wait": 50}'
Ответ
{
  "id": "ph_2758eedebf08496f87e0",
  "object": "phone",
  "status": "starting",
  "name": null,
  "user": null,
  "metadata": null,
  "startup_apps": [{ "source": "https://f-droid.org/F-Droid.apk", "status": "pending" }],
  "created_at": 1793308400,
  "ready_at": null,
  "last_active_at": 1793308400,
  "deletes_after_idle_at": 1793312000,
  "awake_seconds": 0,
  "charge_usd": 0,
  "deleted_at": null,
  "end_reason": null,
  "error": null,
  "price_per_hour_usd": 1.20
}

Получение телефона#

GET/v1/phones/{id}

Возвращает объект телефона. С wait (в секундах, до 50) запрос к телефону в статусе starting удерживается, пока тот не будет готов.

Список телефонов#

GET/v1/phones

Возвращает {"object": "list", "data": [phone, …]}, сначала новые. user= оставляет телефоны одного конечного пользователя; all=1 включает удалённые.

Удаление телефона#

DELETE/v1/phones/{id}

Удаляет телефон вместе с его приложениями и данными, останавливает его запуск и рассчитывает последние минуты. Возвращает объект телефона со статусом deleted. Телефон также удаляется сам через 1 час без активности.

Получение скриншота#

GET/v1/phones/{id}/screenshot

Возвращает текущий экран как изображение WebP (image/webp, 540 пикселей по короткой стороне). С format=json возвращает {screenshot, width, height, app, elements} с изображением в base64.

cURL
curl https://lovelyrouter.com/v1/phones/ph_2758eedebf08496f87e0/screenshot \
  -H "Authorization: Bearer $LOVELY_API_KEY" -o screen.webp

Список элементов#

GET/v1/phones/{id}/elements

Что находится на экране, по дереву представлений Android: {"app", "activity", "width", "height", "data": [element, …]}. У каждого элемента есть id, type (Button, EditText, TextView…), text, desc (метка специальных возможностей), resource (id представления), x и y (его центр), w и h, а также flags (clickable, long-clickable, scrollable, editable, checked/unchecked, focused, selected, password, disabled). На экранах, отрисованных без представлений (игры, некоторые canvas), элементов мало: используйте скриншот.

Отправка действия#

POST/v1/phones/{id}/actions

Выполняет одно действие на телефоне и возвращает {"ok": true} (или ok: false с error). Добавьте "screenshot": true, чтобы получить screenshot (WebP в base64) после того, как экран успокоится. Возвращает 409, пока телефоном управляет запуск агента.

Действия

{"action": "tap", "x", "y"}

Нажать на точку.

{"action": "long_press", "x", "y", "ms"?}

Нажать и удерживать (по умолчанию 800 мс).

{"action": "swipe", "x", "y", "to_x", "to_y", "ms"?}

Провести от одной точки к другой (по умолчанию 300 мс).

{"action": "scroll", "direction", "x"?, "y"?}

up, down, left или right; down показывает то, что ниже. В заданной точке или в центре экрана.

{"action": "type", "text", "clear"?, "submit"?}

Ввести текст в поле с фокусом, на любом языке. clear сначала очищает поле; submit затем нажимает Enter.

{"action": "key", "key"}

back, home, enter, recents, delete, tab, escape, search, menu, power, volume_up, volume_down или wakeup.

{"action": "open_url", "url"}

Открыть ссылку: веб-страницу в Chrome или ссылку на приложение (market://, собственная схема приложения).

{"action": "launch", "package"}

Открыть установленное приложение, например org.fdroid.fdroid.

{"action": "stop_app", "package"}

Принудительно остановить приложение.

{"action": "wait", "seconds"}

До 60 секунд.

{"action": "rotate", "orientation"}

Повернуть телефон: portrait или landscape. Приложение, зафиксированное в одной ориентации (многие игры), её сохраняет. Экран в реальном времени поворачивается следом.

{"action": "shell", "command"}

Команда adb shell на телефоне; в ответе есть output.

cURL
curl https://lovelyrouter.com/v1/phones/ph_2758eedebf08496f87e0/actions \
  -H "Authorization: Bearer $LOVELY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"action": "type", "text": "天气 Tokyo", "submit": true}'
POST/v1/phones/{id}/screen

Возвращает {"url", "expires_at"}: страницу с экраном телефона в реальном времени. Любой, у кого есть ссылка, может смотреть на телефон и управлять им мышью и клавиатурой, поэтому передавайте её только тому, кто должен им пользоваться. Страницу можно встроить в iframe.

Параметры тела запроса

ttl_secondsintegerПо умолчанию 3600

Сколько действует ссылка: от 60 до 86 400. Уже открытый экран продолжает работать.

view_onlyboolean

Открывает страницу в режиме только просмотра. Это настройка отображения, а не разрешение: зритель может её отключить.

Установка приложения#

POST/v1/phones/{id}/apps

Скачивает и устанавливает приложение и отвечает, когда всё готово: {"ok", "packages", "error"} (422, если установка не удалась). Установка уже имеющегося приложения обновляет его.

Параметры тела запроса

urlstring

Ссылка https:// на файл .apk, .apks или .xapk.

apkstring

GET /v1/phones/{id}/apps выводит имена пакетов установленных приложений, а DELETE /v1/phones/{id}/apps/{package} удаляет одно из них.

Загрузка APK#

PUT/v1/phones/apks/{name}

Сохраняет APK, чтобы его можно было установить на любой телефон по name (буквы, цифры, _, ., -; до 80 символов). Отправьте файл телом запроса, до 100 МБ; файл побольше (до 500 МБ) загружайте частями. Подходят файлы .apk, .apks и .xapk; игровые данные .xapk (файлы OBB) копируются на телефон при установке. Загрузка под тем же именем заменяет файл. Возвращает 201 с {name, bytes, sha256}. Каждый аккаунт может хранить 50 файлов, а хранение сверх 1 ГБ оплачивается.

GET /v1/phones/apks выводит их список, а DELETE /v1/phones/apks/{name} удаляет один из них.

cURL
curl -X PUT https://lovelyrouter.com/v1/phones/apks/myapp.apk \
  -H "Authorization: Bearer $LOVELY_API_KEY" \
  --data-binary @myapp.apk

Загрузка большого APK#

POST/v1/phones/apks/{name}/uploads

Файл больше 100 МБ, до 500 МБ, загружайте частями. Начните с указания размера файла, отправьте каждую часть, затем завершите загрузку. Результат тот же, что и при Загрузке APK: файл сохраняется под name и заменяет файл с таким именем.

Параметры тела запроса

bytesintegerОбязательно

Размер файла в байтах, до 524 288 000 (500 МБ).

Возвращается 201 с {id, part_size, parts, parts_done, expires_at}. Затем:

  1. PUT /v1/phones/apks/{name}/uploads/{id}/{n} для каждой части n от 1 до parts, с байтами файла начиная с (n-1) × part_size в теле. Каждая часть занимает part_size байт (50 МБ), кроме последней, в которой остаток. Части можно отправлять в любом порядке или одновременно, а повторно отправленная часть заменяет предыдущую.
  2. POST /v1/phones/apks/{name}/uploads/{id}/complete объединяет части и возвращает 201 с {name, bytes, sha256} или 409 со списком ещё не полученных частей.

GET /v1/phones/apks/{name}/uploads/{id} показывает, какие части пришли (parts_done), а DELETE по этому адресу отменяет загрузку. Загрузка, не завершённая в течение 24 часов, отбрасывается.

Хранение#

Первый 1 ГБ загруженных APK хранится бесплатно. Сверх этого хранение стоит $0.30 за ГБ в месяц и списывается с баланса каждый час. Удаляйте ненужные APK через DELETE /v1/phones/apks/{name}. Для загрузки баланс должен быть больше нуля.

cURL
# 120 MB file: 3 parts
curl https://lovelyrouter.com/v1/phones/apks/game.xapk/uploads \
  -H "Authorization: Bearer $LOVELY_API_KEY" \
  -H "content-type: application/json" \
  -d "{\"bytes\": $(stat -c %s game.xapk)}"

split -b 50M -d -a 2 game.xapk part.
for n in 1 2 3; do
  curl -X PUT https://lovelyrouter.com/v1/phones/apks/game.xapk/uploads/upl_.../$n \
    -H "Authorization: Bearer $LOVELY_API_KEY" \
    --data-binary @part.0$((n-1))
done

curl -X POST https://lovelyrouter.com/v1/phones/apks/game.xapk/uploads/upl_.../complete \
  -H "Authorization: Bearer $LOVELY_API_KEY"

Объект запуска#

Атрибуты

idstring

prun_ и 20 символов.

objectstring

Всегда phone.run.

phone_idstring

Телефон, на котором выполняется запуск.

statusstring

queued (телефон запускается), running, waiting (агент задал вам вопрос), succeeded, failed или stopped (вами или по достижении max_steps).

goalmodel

То, что вы отправили.

stepsinteger

Число шагов на данный момент.

questionstring | null

Во время waiting: что агенту нужно от вас.

answerstring | null

Результат, когда запуск завершён.

errorstring | null

Почему запуск завершился сбоем или был остановлен.

llm_usdnumber

Стоимость токенов модели (задаётся по окончании запуска).

tracearray

С trace=1: для каждого шага step, note (что агент увидел и почему так поступил), action, args, app, ok, error и ms, а также unchanged: true, если действие оставило экран в точности прежним.

Запуск агента#

POST/v1/phones/runs

Создаёт телефон и запускает на нём агента или запускает его на одном из ваших телефонов, указанном в phone_id. Возвращает 202 с объектом запуска. Телефон выполняет одну цель за раз: 409, пока на нём активен другой запуск.

Параметры тела запроса

goalstringОбязательно

Что сделать, простыми словами, со всеми значениями, которые нужны для задачи. До 10 000 символов.

phone_idstring

Выполнить на этом телефоне вместо нового. POST /v1/phones/{id}/runs делает то же самое.

appsname

Для нового телефона, как в Создании телефона.

modestringПо умолчанию smart

smart: модель решает каждый шаг (по несколько секунд на шаг). fast: быстрая модель принятия решений выбирает почти каждый шаг гораздо быстрее секунды (она всегда действует, что подходит для игр), а model только пишет ответ или вопрос для вас. См. Быстрый режим.

planbooleanПо умолчанию true

Только в быстром режиме: рядом с быстрой моделью работает модель-тренер (входит в цену телефона). Она пишет короткую стратегию для цели (для игры — какие ходы предпочитать) и заметку о текущей ситуации и переписывает их каждые несколько шагов или когда запуск, похоже, застрял. Быстрая модель никогда её не ждёт: на каждом шаге используется последняя версия. Запуск показывает их в strategy, situation и sidecar_updates.

modelstringПо умолчанию gemini-3.8-flash

Любая модель чата из GET /v1/models. Её токены оплачиваются по обычной цене.

max_stepsintegerПо умолчанию 40

От 1 до 200. Запуск, достигший этого предела, завершается как stopped с error reached the step limit (N).

waitinteger

Сколько секунд удерживать запрос, пока запуск не завершится или не задаст вопрос, до 50.

Получение запуска#

GET/v1/phones/runs/{id}

Возвращает объект запуска. wait (до 50 секунд) удерживает запрос, пока запуск не завершится или не задаст вам вопрос; trace=1 добавляет шаги, а after_step=N дополнительно отвечает, как только у запуска станет больше N шагов. GET /v1/phones/runs?phone_id= выводит запуски, сначала новые.

Ответ на вопрос запуска#

POST/v1/phones/runs/{id}/reply

Отвечает на question запуска через {"answer": "…"}; запуск продолжается. Возвращает 409, если запуск не ожидает ответа.

Остановка запуска#

POST/v1/phones/runs/{id}/stop

Останавливает запуск после текущего шага. Телефон остаётся.

Ошибки#

| Статус | Когда | | - | - | | 400 | Поле отсутствует или указано неверно; в сообщении сказано, какое именно. | | 402 | Баланса не хватает для запуска телефона, или он исчерпан. | | 404 | В вашем аккаунте нет такого телефона, запуска или APK. | | 409 | Телефон ещё запускается или занят запуском агента. | | 410 | Телефон удалён. | | 413 | APK слишком велик для одного запроса (больше 100 МБ: загрузите его частями) или больше 500 МБ. | | 422 | Приложение не установилось; причина указана в error. | | 429 | У вас уже есть 3 телефона или 50 загруженных APK. | | 503 | Сейчас заняты все телефоны; повторите попытку через несколько минут. |