Saltar al contenido

Webhooks

MoreLogin puede enviar por POST un evento JSON al endpoint HTTPS que tú controlas en cuanto una operación de cloud phone o cloud browser alcanza su resultado final, así que ya no tienes que hacer polling para conocerlo. Se almacena una sola URL de callback por equipo, y la Local API y la Open API escriben en el mismo registro.

Configurar la URL de callback

Ambos entornos exponen la misma operación. 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
  }'

La ruta de la Local API la sirve el cliente de escritorio, así que necesita el cliente de MoreLogin v2.66.0 o superior. El endpoint de la Open API no depende del cliente.

teamId nunca se lee de la petición. Cada llamada configura el equipo del contexto del servidor, así que no puedes dirigir los eventos de otro equipo a tu endpoint.

La URL debe ser HTTPS, de 1 a 1024 caracteres, con host, sin información de usuario, sin fragmento y con un puerto válido. Todas las direcciones a las que resuelva tienen que ser enrutables públicamente: los rangos de localhost, privados, link-local, CGNAT, metadatos de nube, reservados por protocolo, de documentación y 6to4 se rechazan con 41001. La misma comprobación se repite cuando una entrega abre su conexión, así que un nombre de host que más tarde resuelva a un rango privado hace fallar esa entrega en lugar de llegar a tu red.

El guardado es un upsert por equipo, así que enviar el mismo cuerpo dos veces es inofensivo.

Desactivar la entrega

enabled: false mantiene la URL guardada y detiene la creación de nuevos eventos. Los eventos ya en cola se cancelan uno a uno, en el momento en que a cada uno le tocaría autorizarse, y solo mientras la configuración siga desactivada: si la reactivas pronto, los eventos en cola continúan en lugar de descartarse.

Cómo es una entrega

Cada entrega es un POST con estas cabeceras:

CabeceraValor
Content-Typeapplication/json
User-AgentMoreLogin-Webhook/1.0
X-Webhook-Event-IdIgual que eventId en el cuerpo
X-Webhook-Event-TypeIgual que eventType en el cuerpo

Las dos cabeceras X-Webhook-* duplican campos del cuerpo a propósito, para que un router o una cola puedan repartir con ellas sin analizar el 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
  }
}
CampoDescripción
eventIdID de evento único. Los reintentos y las repeticiones internas del mismo evento lo reutilizan, así que es la clave de idempotencia
eventTypeNombre de evento estable, de la tabla siguiente
eventTimeCuándo ocurrió el resultado final, en milisegundos de época Unix. Se envía como cadena
data.teamIdEquipo propietario del recurso. Se envía como cadena
data.cloudPhoneIdCloud phone al que se refiere el evento. Se envía como cadena
data.cloudBrowserIdPerfil de cloud browser al que se refiere el evento. Se envía como cadena
data.runIdInstancia de ejecución de cloud browser a la que se refiere el evento
data.reasonSolo en cloud_phone.power_off y cloud_browser.stop
result.successSi la operación finalmente tuvo éxito
result.code0 en caso de éxito; si no, un código de error de negocio estable que no depende del idioma
result.messagenull en caso de éxito; si no, una explicación en el idioma del equipo, con reserva a en-US

Todos los identificadores numéricos y eventTime llegan como cadenas JSON, igual que en el resto de la API: consulta Formato común de respuesta. Interprétalos como cadenas y no como números, o perderás precisión en los ID de 64 bits.

Eventos

eventTypeResultado final que informa
cloud_phone.power_onEncendido correcto o fallido
cloud_phone.power_offApagado correcto. Un apagado fallido no produce evento
cloud_phone.restartReinicio correcto o fallido
cloud_phone.resetRestablecimiento correcto o fallido
cloud_phone.new_machineNuevo dispositivo con un clic correcto o fallido
cloud_browser.startInicio del cloud browser correcto o fallido
cloud_browser.stopCada intento de cierre del cloud browser, con éxito o sin él

Los eventos de cloud phone llevan teamId y cloudPhoneId. Los de cloud browser llevan teamId, cloudBrowserId y runId.

El encendido, el reinicio, el restablecimiento y el nuevo dispositivo con un clic informan success: true solo una vez que la devolución de llamada del servicio tuvo éxito y la sincronización local se confirmó. Un fallo de facturación, o una comprobación de proxy asíncrona que falla y completa su limpieza, informa de un encendido fallido y no emite además un apagado. El trabajo diferido, como instalar aplicaciones preinstaladas o limpiar archivos caducados, no cambia el resultado.

Si un apagado interrumpe un arranque, ese intento no produce evento de encendido; el apagado correcto posterior sí produce su propio cloud_phone.power_off.

Motivos de detención

cloud_phone.power_off añade data.reason:

ValorSignificado
NORMALApagado ordinario
MONEY_SAVINGModo de ahorro de dinero
OTHERImpagos, caducidad, mantenimiento o cualquier otra causa

cloud_browser.stop añade data.reason:

ValorSignificado
NORMALCierre ordinario
MONEY_SAVINGModo de ahorro de dinero
ENERGY_SAVINGModo de ahorro de energía
BROWSER_EXITEDEl navegador se cerró de forma inesperada
OTHERCualquier otra causa

Un fallo interno de archivado solo cambia result; nunca sobrescribe el reason capturado cuando comenzó el cierre.

Entrega, reintentos y orden

Cualquier 2xx cuenta como entregado. Cualquier otro estado, más los tiempos de espera de conexión y de lectura y los errores de red, cuenta como fallo. El tiempo de espera de conexión es de 5 segundos y el de lectura, de 30 segundos.

Una entrega fallida se reintenta como máximo 6 veces, a los 10 segundos, 30 segundos, 60 segundos, 3 minutos, 10 minutos y 30 minutos. Son como máximo 7 peticiones para un evento. Cuando falla el sexto reintento, el evento deja de reintentarse automáticamente.

Los eventos de un mismo cloud phone, o de un mismo cloud browser, se entregan en orden de creación, de uno en uno. Los recursos distintos se entregan en paralelo, así que no asumas ningún orden entre ellos.

Los reintentos de un evento reutilizan siempre el mismo eventId, eventTime y cuerpo. En situaciones límite de red o de recuperación, el mismo evento puede entregarse más de una vez con esos valores sin cambios, así que deduplica por eventId.

En los cierres de cloud browser, un intento de cierre produce exactamente un evento. Un reintento manual posterior, una liberación forzada manual o una liberación forzada iniciada por el sistema son una operación nueva y reciben un eventId nuevo. Dos intentos nunca se fusionan en un solo evento.

Las operaciones de cloud phone se identifican por el ID de tarea del servicio, traceId o una marca de tiempo de negocio estable. Cuando no existe ninguno, el servicio genera un UUID y trata la devolución de llamada final actual como una operación nueva, así que recibes un eventId nuevo en lugar de que dos operaciones distintas se colapsen en una.

Escribir el receptor

Devuelve un 2xx en cuanto hayas almacenado el evento, y haz el trabajo real de forma asíncrona. El cuerpo de la respuesta se ignora, y un manejador lento consume tus 30 segundos de lectura y empuja el evento al calendario de reintentos aunque lo hayas recibido.

Deduplica por eventId. Trata una repetición como ya gestionada en lugar de repetir los efectos secundarios.

No trates la carga como entrada de confianza solo porque llegó a tu endpoint. Esta versión no firma los callbacks, así que cualquiera que conozca tu URL puede publicar en ella. Usa una URL difícil de adivinar y, antes de hacer algo costoso, confirma el estado a través de la API: por ejemplo POST /cloudphone/info para un cloud phone, o POST /cloudbrowser/page para una ejecución de cloud browser.

result.code usa los mismos códigos de negocio que la API sincrónica, así que un fallo se puede consultar en Códigos de error. result.message es una cadena legible cuyo texto e idioma pueden cambiar; ramifica según result.success y result.code, nunca según result.message.

El contrato legible por máquina de cada evento, incluidos los esquemas y los ejemplos por evento, se publica con la especificación de recursos compartidos en Shared Resources Open API.