Skip to content

Webhook

MoreLogin có thể POST một sự kiện JSON tới endpoint HTTPS do bạn quản lý ngay khi một thao tác cloud phone hoặc cloud browser có kết quả cuối cùng, nên bạn không còn phải polling để biết kết quả. Mỗi nhóm chỉ lưu một URL callback, và Local API cùng Open API ghi vào cùng một bản ghi.

Cấu hình URL callback

Cả hai bề mặt đều cung cấp cùng một thao tác. 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
  }'

Route của Local API do client máy tính phục vụ, nên cần client MoreLogin v2.66.0 trở lên. Endpoint của Open API không phụ thuộc client.

teamId không bao giờ được đọc từ request. Mỗi lần gọi đều cấu hình cho nhóm thuộc ngữ cảnh phía máy chủ, nên bạn không thể trỏ sự kiện của nhóm khác về endpoint của mình.

URL phải là HTTPS, dài từ 1 đến 1024 ký tự, có tên host, không chứa thông tin người dùng, không có fragment và cổng hợp lệ. Mọi địa chỉ mà nó phân giải ra đều phải định tuyến được trên internet: các dải localhost, riêng tư, link-local, CGNAT, metadata đám mây, dải dành riêng cho giao thức, dải dùng cho tài liệu và 6to4 sẽ bị từ chối với mã 41001. Cùng phép kiểm tra đó được thực hiện lại khi một lần gửi mở kết nối, nên một tên host sau này phân giải vào dải riêng tư chỉ làm lần gửi đó thất bại chứ không chạm tới mạng của bạn.

Việc lưu là upsert theo nhóm, nên gửi cùng một body hai lần cũng không gây hại.

Tắt việc gửi

enabled: false giữ lại URL đã lưu và dừng tạo sự kiện mới. Các sự kiện đã nằm trong hàng đợi sẽ bị hủy lần lượt, vào đúng thời điểm mỗi sự kiện sắp được cấp phép, và chỉ khi cấu hình vẫn đang tắt — nên nếu bạn bật lại sớm, các sự kiện trong hàng đợi sẽ tiếp tục được gửi thay vì bị loại bỏ.

Một lần gửi trông như thế nào

Mỗi lần gửi là một POST với các header sau:

HeaderGiá trị
Content-Typeapplication/json
User-AgentMoreLogin-Webhook/1.0
X-Webhook-Event-IdGiống eventId trong body
X-Webhook-Event-TypeGiống eventType trong body

Hai header X-Webhook-* cố ý trùng với các trường trong body, để router hoặc queue có thể phân phối theo chúng mà không cần phân tích 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
  }
}
TrườngMô tả
eventIdID sự kiện duy nhất. Các lần thử lại và phát lại nội bộ của cùng sự kiện đều dùng lại nó, nên đây là khóa idempotency
eventTypeTên sự kiện ổn định, lấy từ bảng dưới
eventTimeThời điểm kết quả cuối cùng xảy ra, tính bằng milli giây epoch Unix. Được gửi dưới dạng chuỗi
data.teamIdNhóm sở hữu tài nguyên. Được gửi dưới dạng chuỗi
data.cloudPhoneIdCloud phone mà sự kiện nói về. Được gửi dưới dạng chuỗi
data.cloudBrowserIdProfile cloud browser mà sự kiện nói về. Được gửi dưới dạng chuỗi
data.runIdPhiên chạy cloud browser mà sự kiện nói về
data.reasonChỉ có ở cloud_phone.power_off và cloud_browser.stop
result.successThao tác cuối cùng có thành công hay không
result.code0 khi thành công; nếu không thì là mã lỗi nghiệp vụ ổn định, không phụ thuộc ngôn ngữ
result.messagenull khi thành công; nếu không thì là phần giải thích theo ngôn ngữ của nhóm, quay về en-US khi thiếu

Mọi định danh dạng số và eventTime đều đến dưới dạng chuỗi JSON, giống phần còn lại của API — xem Định dạng phản hồi chung. Hãy phân tích chúng như chuỗi thay vì số, nếu không bạn sẽ mất độ chính xác với ID 64-bit.

Sự kiện

eventTypeKết quả cuối cùng mà nó báo
cloud_phone.power_onBật thành công hoặc thất bại
cloud_phone.power_offTắt thành công. Lần tắt thất bại không tạo sự kiện
cloud_phone.restartKhởi động lại thành công hoặc thất bại
cloud_phone.resetĐặt lại thành công hoặc thất bại
cloud_phone.new_machineTạo máy mới một lần bấm thành công hoặc thất bại
cloud_browser.startMở cloud browser thành công hoặc thất bại
cloud_browser.stopMỗi lần thử đóng cloud browser, dù thành công hay không

Sự kiện cloud phone mang theo teamId và cloudPhoneId. Sự kiện cloud browser mang theo teamId, cloudBrowserId và runId.

Bật, khởi động lại, đặt lại và tạo máy mới một lần bấm chỉ báo success: true sau khi callback của dịch vụ thiết bị thành công và việc đồng bộ cục bộ đã commit. Lỗi tính phí khi bật, hoặc một lần kiểm tra proxy bất đồng bộ thất bại và hoàn tất dọn dẹp, đều báo là bật thất bại và không tạo thêm sự kiện tắt. Các việc hoãn lại như cài ứng dụng mặc định hay xóa tệp đã hết hạn không làm thay đổi kết quả.

Nếu một lần tắt làm gián đoạn quá trình bật, lần thử đó không tạo sự kiện bật; lần tắt thành công sau đó vẫn tạo cloud_phone.power_off riêng.

Lý do dừng

cloud_phone.power_off bổ sung data.reason:

Giá trịÝ nghĩa
NORMALTắt thông thường
MONEY_SAVINGChế độ tiết kiệm chi phí
OTHERNợ phí, hết hạn, bảo trì hoặc lý do khác

cloud_browser.stop bổ sung data.reason:

Giá trịÝ nghĩa
NORMALĐóng thông thường
MONEY_SAVINGChế độ tiết kiệm chi phí
ENERGY_SAVINGChế độ tiết kiệm năng lượng
BROWSER_EXITEDTrình duyệt thoát ngoài dự kiến
OTHERLý do khác

Lỗi lưu trữ nội bộ chỉ ảnh hưởng tới result; nó không bao giờ ghi đè reason đã chốt khi bắt đầu đóng.

Gửi, thử lại và thứ tự

Mọi mã 2xx đều tính là đã gửi thành công. Mọi trạng thái khác, cùng với timeout kết nối, timeout đọc và lỗi mạng, đều tính là thất bại. Timeout kết nối là 5 giây và timeout đọc là 30 giây.

Một lần gửi thất bại sẽ được thử lại tối đa 6 lần, sau 10 giây, 30 giây, 60 giây, 3 phút, 10 phút và 30 phút. Tức là tối đa 7 request cho một sự kiện. Sau khi lần thử lại thứ sáu thất bại, sự kiện sẽ ngừng được thử lại tự động.

Sự kiện của cùng một cloud phone, hoặc cùng một cloud browser, được gửi theo thứ tự tạo, mỗi lần một sự kiện. Các tài nguyên khác nhau được gửi song song, nên đừng giả định có thứ tự nào giữa chúng.

Các lần thử lại của một sự kiện luôn dùng lại cùng eventId, eventTime và body. Trong các tình huống biên về mạng hoặc phục hồi, cùng một sự kiện có thể được gửi nhiều lần với các giá trị đó không đổi, nên hãy loại trùng theo eventId.

Với việc đóng cloud browser, một lần thử đóng tạo ra đúng một sự kiện. Lần thử lại thủ công sau đó, lần giải phóng cưỡng bức thủ công, hoặc lần giải phóng cưỡng bức do hệ thống khởi tạo đều là thao tác mới và nhận eventId mới. Hai lần thử không bao giờ bị gộp thành một sự kiện.

Các thao tác cloud phone được nhận diện qua ID tác vụ của dịch vụ thiết bị, traceId, hoặc một mốc thời gian nghiệp vụ ổn định. Khi không có cái nào, dịch vụ sinh một UUID và coi callback cuối cùng hiện tại là thao tác mới, nên bạn nhận được eventId mới thay vì hai thao tác khác nhau bị gộp thành một.

Viết phía nhận

Hãy trả về 2xx ngay khi bạn đã lưu sự kiện, và xử lý thật sự theo cách bất đồng bộ. Body phản hồi bị bỏ qua, và một handler chậm sẽ tiêu hết 30 giây đọc của bạn rồi đẩy sự kiện vào lịch thử lại dù bạn đã nhận được nó.

Hãy loại trùng theo eventId. Coi một lần trùng là đã xử lý thay vì chạy lại các tác dụng phụ.

Đừng coi payload là dữ liệu đáng tin chỉ vì nó đã tới endpoint của bạn. Bản phát hành này không ký callback, nên bất kỳ ai biết URL của bạn đều có thể gửi tới đó. Hãy dùng URL khó đoán, và trước khi làm việc gì tốn kém, hãy xác nhận trạng thái qua API — ví dụ POST /cloudphone/info cho cloud phone, hoặc POST /cloudbrowser/page cho một phiên chạy cloud browser.

result.code dùng cùng bộ mã nghiệp vụ với API đồng bộ, nên có thể tra một lần thất bại trong Mã lỗi. result.message là chuỗi dành cho người đọc, câu chữ và ngôn ngữ đều có thể thay đổi; hãy rẽ nhánh theo result.success và result.code, đừng bao giờ theo result.message.

Hợp đồng máy đọc được của từng sự kiện, gồm schema và ví dụ cho từng sự kiện, được công bố cùng đặc tả shared resources tại Shared Resources Open API.