MoreLogin може надсилати JSON-подію методом POST на ваш HTTPS-ендпоінт відразу після того, як операція з хмарним телефоном або хмарним браузером досягла підсумкового результату, тому опитувати результат більше не потрібно. На команду зберігається один URL зворотного виклику, і Local API та Open API пишуть в один і той самий запис.
Обидва контури надають ту саму операцію. Open API:
curl -X POST "https://api.morelogin.com/webhook/config" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"callbackUrl": "https://example.com/morelogin/webhook",
"enabled": true
}'Local API:
curl -X POST "http://127.0.0.1:40000/api/webhook/config" \
-H "Content-Type: application/json" \
-d '{
"callbackUrl": "https://example.com/morelogin/webhook",
"enabled": true
}'Маршрут Local API обслуговує настільний клієнт, тому потрібен клієнт MoreLogin v2.66.0 або новіший. Ендпоінт Open API від клієнта не залежить.
teamId ніколи не читається із запиту. Кожен виклик налаштовує команду із серверного контексту, тому спрямувати події іншої команди на свій ендпоінт не вийде.
URL має бути HTTPS, довжиною від 1 до 1024 символів, з іменем хоста, без даних користувача, без фрагмента та з коректним портом. Усі адреси, у які він розв'язується, повинні маршрутизуватися в інтернеті: діапазони localhost, приватні, link-local, CGNAT, метаданих хмари, зарезервовані протоколом, документаційні та 6to4 відхиляються з кодом 41001. Та сама перевірка повторюється в момент, коли доставка відкриває з'єднання, тому імʼя хоста, яке згодом розв'яжеться у приватний діапазон, призведе до невдачі цієї доставки, а не до звернення у вашу мережу.
Збереження — це upsert за командою, тому надіслати те саме тіло двічі безпечно.
enabled: false зберігає URL і припиняє створення нових подій. Уже поставлені в чергу події скасовуються по одній, у той момент, коли кожну з них має бути авторизовано, і лише поки конфігурація все ще вимкнена — тому при швидкому повторному ввімкненні події з черги продовжать доставлятися, а не будуть відкинуті.
Кожна доставка — це POST із такими заголовками:
| Заголовок | Значення |
|---|---|
Content-Type | application/json |
User-Agent | MoreLogin-Webhook/1.0 |
X-Webhook-Event-Id | Те саме, що eventId у тілі |
X-Webhook-Event-Type | Те саме, що eventType у тілі |
Два заголовки X-Webhook-* навмисно дублюють поля тіла, щоб маршрутизатор або черга могли розподіляти запити за ними без розбору JSON.
{
"eventId": "c7f3a2b10d8e4f6a9c1b2d3e4f5a6b7c",
"eventType": "cloud_phone.power_off",
"eventTime": "1787241600000",
"data": {
"teamId": "10001",
"cloudPhoneId": "20001",
"reason": "MONEY_SAVING"
},
"result": {
"success": true,
"code": "0",
"message": null
}
}| Поле | Опис |
|---|---|
eventId | Унікальний ID події. Повтори та внутрішні відтворення тієї самої події використовують його повторно, тому це ключ ідемпотентності |
eventType | Стабільна назва події з таблиці нижче |
eventTime | Коли настав підсумковий результат, у мілісекундах епохи Unix. Передається рядком |
data.teamId | Команда, якій належить ресурс. Передається рядком |
data.cloudPhoneId | Хмарний телефон, до якого стосується подія. Передається рядком |
data.cloudBrowserId | Профіль хмарного браузера, до якого стосується подія. Передається рядком |
data.runId | Екземпляр запуску хмарного браузера, до якого стосується подія |
data.reason | Лише у cloud_phone.power_off та cloud_browser.stop |
result.success | Чи завершилася операція успішно |
result.code | 0 у разі успіху; інакше стабільний бізнес-код помилки, що не залежить від мови |
result.message | null у разі успіху; інакше пояснення мовою команди з переходом на en-US |
Усі числові ідентифікатори та eventTime надходять рядками JSON, як і в решті API — див. Загальний формат відповіді. Розбирайте їх як рядки, а не як числа, інакше втратите точність на 64-бітних ID.
eventType | Підсумковий результат, про який повідомляється |
|---|---|
cloud_phone.power_on | Увімкнення вдалося або не вдалося |
cloud_phone.power_off | Вимкнення вдалося. Невдале вимкнення події не створює |
cloud_phone.restart | Перезапуск удався або не вдався |
cloud_phone.reset | Скидання вдалося або не вдалося |
cloud_phone.new_machine | Новий пристрій одним клацанням удався або не вдався |
cloud_browser.start | Запуск хмарного браузера вдався або не вдався |
cloud_browser.stop | Кожна спроба зупинки хмарного браузера, успішна чи ні |
Події хмарного телефона містять teamId та cloudPhoneId. Події хмарного браузера містять teamId, cloudBrowserId і runId.
Увімкнення, перезапуск, скидання та створення нового пристрою одним клацанням повідомляють success: true лише після того, як зворотний виклик сервісу був успішним і локальна синхронізація зафіксована. Помилка списання коштів або асинхронна перевірка проксі, яка завершилася невдало та довела до кінця своє очищення, повідомляють про невдале увімкнення і не створюють додатково подію вимкнення. Відкладені задачі, наприклад встановлення попередньо визначених застосунків або видалення застарілих файлів, результат не змінюють.
Якщо вимкнення перервало завантаження, ця спроба не створює події увімкнення; успішне вимкнення згодом усе одно створить власне cloud_phone.power_off.
cloud_phone.power_off додає data.reason:
| Значення | Сенс |
|---|---|
NORMAL | Звичайне вимкнення |
MONEY_SAVING | Режим економії коштів |
OTHER | Заборгованість, завершення терміну, обслуговування або інша причина |
cloud_browser.stop додає data.reason:
| Значення | Сенс |
|---|---|
NORMAL | Звичайне закриття |
MONEY_SAVING | Режим економії коштів |
ENERGY_SAVING | Режим енергозбереження |
BROWSER_EXITED | Браузер завершився неочікувано |
OTHER | Будь-яка інша причина |
Внутрішня помилка архівування змінює лише result і ніколи не перезаписує reason, зафіксований на початку зупинки.
Будь-який 2xx вважається доставкою. Будь-який інший статус, а також тайм-аути з'єднання та читання і мережеві помилки вважаються невдачею. Тайм-аут з'єднання — 5 секунд, тайм-аут читання — 30 секунд.
Невдала доставка повторюється не більше 6 разів: через 10 секунд, 30 секунд, 60 секунд, 3 хвилини, 10 хвилин і 30 хвилин. Це не більше 7 запитів на одну подію. Після невдачі шостого повтору подія перестає повторюватися автоматично.
Події одного хмарного телефона або одного хмарного браузера доставляються в порядку створення, по одній. Різні ресурси доставляються паралельно, тому не покладайтеся на якийсь порядок між ними.
Повтори однієї події завжди використовують ті самі eventId, eventTime і тіло. У межових мережевих або відновлювальних ситуаціях та сама подія може бути доставлена кілька разів із незмінними значеннями, тому дедуплікуйте за eventId.
Для зупинок хмарного браузера одна спроба зупинки дає рівно одну подію. Подальший повтор вручну, примусове звільнення вручну або примусове звільнення, ініційоване системою, — це нова операція, яка отримує новий eventId. Дві спроби ніколи не об'єднуються в одну подію.
Операції хмарного телефона визначаються за ID задачі сервісу, traceId або стабільною бізнес-позначкою часу. Коли жодного з них немає, сервіс генерує UUID і вважає поточний підсумковий зворотний виклик новою операцією, тому ви отримуєте новий eventId, а дві різні операції не зливаються в одну.
Повертайте 2xx відразу після того, як зберегли подію, а реальну роботу виконуйте асинхронно. Тіло відповіді ігнорується, а повільний обробник витратить ваші 30 секунд на читання і відправить подію до розкладу повторів, хоча ви її вже отримали.
Дедуплікуйте за eventId. Вважайте повтор уже обробленим, а не відтворюйте побічні ефекти знову.
Не вважайте корисне навантаження довіреним вводом лише тому, що воно надійшло на ваш ендпоінт. У цьому випуску зворотні виклики не підписуються, тому надіслати запит може будь-хто, хто дізнався ваш URL. Використовуйте URL, який важко вгадати, і перш ніж виконувати щось дороге, підтвердьте стан через API — наприклад POST /cloudphone/info для хмарного телефона або POST /cloudbrowser/page для запуску хмарного браузера.
result.code використовує ті самі бізнес-коди, що й синхронний API, тому невдачу можна знайти в Коди помилок. result.message — читабельний для людини рядок, формулювання та мова якого можуть змінюватися; розгалужуйтеся за result.success і result.code, але ніколи за result.message.
Машинно-читний контракт кожної події, включно зі схемами та прикладами по подіях, публікується разом зі специфікацією спільних ресурсів: Shared Resources Open API.