A MoreLogin pode enviar por POST um evento JSON para o endpoint HTTPS que você controla assim que uma operação de cloud phone ou cloud browser chega ao resultado final, então você não precisa mais fazer polling. Uma única URL de callback é armazenada por equipe, e a Local API e a Open API gravam no mesmo registro.
Os dois ambientes expõem a mesma operação. 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
}'A rota da Local API é servida pelo cliente de desktop, então requer o cliente MoreLogin v2.66.0 ou superior. O endpoint da Open API não depende do cliente.
teamId nunca é lido da requisição. Cada chamada configura a equipe do contexto do servidor, então você não pode apontar os eventos de outra equipe para o seu endpoint.
A URL precisa ser HTTPS, com 1 a 1024 caracteres, com host, sem informações de usuário, sem fragmento e com porta válida. Todos os endereços para os quais ela resolver precisam ser roteáveis publicamente: faixas de localhost, privadas, link-local, CGNAT, metadados de nuvem, reservadas por protocolo, de documentação e 6to4 são rejeitadas com 41001. A mesma verificação ocorre de novo quando uma entrega abre a conexão, então um host que depois resolva para uma faixa privada faz aquela entrega falhar em vez de alcançar sua rede.
O salvamento é um upsert por equipe, então enviar o mesmo corpo duas vezes não causa problema.
enabled: false mantém a URL registrada e interrompe a criação de novos eventos. Eventos já na fila são cancelados um a um, no momento em que cada um seria autorizado, e apenas enquanto a configuração continuar desativada — então, se você reativar logo, os eventos na fila continuam em vez de serem descartados.
Cada entrega é um POST com estes cabeçalhos:
| Cabeçalho | Valor |
|---|---|
Content-Type | application/json |
User-Agent | MoreLogin-Webhook/1.0 |
X-Webhook-Event-Id | Igual a eventId no corpo |
X-Webhook-Event-Type | Igual a eventType no corpo |
Os dois cabeçalhos X-Webhook-* duplicam campos do corpo de propósito, para que um roteador ou fila possa distribuir por eles sem fazer parsing do 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
}
}| Campo | Descrição |
|---|---|
eventId | ID de evento único. As novas tentativas e as reexecuções internas do mesmo evento o reutilizam, então ele é a chave de idempotência |
eventType | Nome de evento estável, da tabela abaixo |
eventTime | Quando o resultado final ocorreu, em milissegundos de época Unix. Enviado como string |
data.teamId | Equipe proprietária do recurso. Enviado como string |
data.cloudPhoneId | Cloud phone a que o evento se refere. Enviado como string |
data.cloudBrowserId | Perfil de cloud browser a que o evento se refere. Enviado como string |
data.runId | Instância de execução do cloud browser a que o evento se refere |
data.reason | Apenas em cloud_phone.power_off e cloud_browser.stop |
result.success | Se a operação teve êxito no final |
result.code | 0 em caso de êxito; caso contrário, um código de erro de negócio estável que não depende do idioma |
result.message | null em caso de êxito; caso contrário, uma explicação no idioma da equipe, recorrendo a en-US |
Todos os identificadores numéricos e eventTime chegam como strings JSON, igual ao restante da API — veja Formato de Resposta Comum. Interprete-os como strings, não como números, ou você perderá precisão em IDs de 64 bits.
eventType | Resultado final que ele informa |
|---|---|
cloud_phone.power_on | Ligamento com êxito ou com falha |
cloud_phone.power_off | Desligamento com êxito. Um desligamento com falha não produz evento |
cloud_phone.restart | Reinício com êxito ou com falha |
cloud_phone.reset | Redefinição com êxito ou com falha |
cloud_phone.new_machine | Novo aparelho com um clique, com êxito ou com falha |
cloud_browser.start | Início do cloud browser com êxito ou com falha |
cloud_browser.stop | Cada tentativa de encerramento do cloud browser, com ou sem êxito |
Os eventos de cloud phone carregam teamId e cloudPhoneId. Os de cloud browser carregam teamId, cloudBrowserId e runId.
Ligamento, reinício, redefinição e novo aparelho com um clique informam success: true somente depois que o callback do provedor teve êxito e a sincronização local foi confirmada. Uma falha de cobrança, ou uma verificação de proxy assíncrona que falha e conclui sua limpeza, informa um ligamento com falha e não emite adicionalmente um desligamento. Trabalhos adiados, como instalar aplicativos predefinidos ou limpar arquivos expirados, não alteram o resultado.
Se um desligamento interromper uma inicialização, aquela tentativa não produz evento de ligamento; o desligamento bem-sucedido posterior ainda produz seu próprio cloud_phone.power_off.
cloud_phone.power_off acrescenta data.reason:
| Valor | Significado |
|---|---|
NORMAL | Desligamento comum |
MONEY_SAVING | Modo de economia de dinheiro |
OTHER | Inadimplência, expiração, manutenção ou qualquer outro motivo |
cloud_browser.stop acrescenta data.reason:
| Valor | Significado |
|---|---|
NORMAL | Encerramento comum |
MONEY_SAVING | Modo de economia de dinheiro |
ENERGY_SAVING | Modo de economia de energia |
BROWSER_EXITED | O navegador encerrou de forma inesperada |
OTHER | Qualquer outro motivo |
Uma falha interna de arquivamento altera apenas result; nunca sobrescreve o reason capturado quando o encerramento começou.
Qualquer 2xx conta como entregue. Qualquer outro status, além de tempos limite de conexão e de leitura e erros de rede, conta como falha. O tempo limite de conexão é de 5 segundos e o de leitura, de 30 segundos.
Uma entrega com falha é repetida no máximo 6 vezes, após 10 segundos, 30 segundos, 60 segundos, 3 minutos, 10 minutos e 30 minutos. São no máximo 7 requisições para um evento. Depois que a sexta tentativa falha, o evento para de ser repetido automaticamente.
Eventos do mesmo cloud phone, ou do mesmo cloud browser, são entregues na ordem de criação, um por vez. Recursos diferentes são entregues em paralelo, então não presuma nenhuma ordem entre eles.
As novas tentativas de um evento sempre reutilizam o mesmo eventId, eventTime e corpo. Em situações limite de rede ou de recuperação, o mesmo evento pode ser entregue mais de uma vez com esses valores inalterados, então deduplique por eventId.
Para encerramentos de cloud browser, uma tentativa de encerramento gera exatamente um evento. Uma nova tentativa manual posterior, uma liberação forçada manual ou uma liberação forçada iniciada pelo sistema são uma operação nova e recebem um novo eventId. Duas tentativas nunca são mescladas em um único evento.
As operações de cloud phone são identificadas pelo ID de tarefa do provedor, traceId ou um carimbo de tempo de negócio estável. Quando nenhum deles existe, o serviço gera um UUID e trata o callback final atual como uma operação nova, então você recebe um novo eventId em vez de duas operações distintas se juntarem em uma.
Retorne um 2xx assim que tiver armazenado o evento e faça o trabalho real de forma assíncrona. O corpo da resposta é ignorado, e um handler lento consome seus 30 segundos de leitura e empurra o evento para a fila de novas tentativas mesmo que você já o tenha recebido.
Deduplique por eventId. Trate uma repetição como já processada em vez de repetir os efeitos colaterais.
Não trate o payload como entrada confiável só porque ele chegou ao seu endpoint. Esta versão não assina os callbacks, então qualquer pessoa que descobrir sua URL pode enviar para ela. Use uma URL difícil de adivinhar e, antes de fazer algo custoso, confirme o estado pela API — por exemplo POST /cloudphone/info para um cloud phone, ou POST /cloudbrowser/page para uma execução de cloud browser.
result.code usa os mesmos códigos de negócio da API sincrônica, então uma falha pode ser consultada em Códigos de erro. result.message é uma string legível cujo texto e idioma podem mudar; ramifique por result.success e result.code, nunca por result.message.
O contrato legível por máquina de cada evento, incluindo esquemas e exemplos por evento, é publicado com a especificação de recursos compartilhados em Shared Resources Open API.