Skip to main content

Visão Geral

O webhook de Nova Mensagem é disparado pela Morada.ai sempre que uma mensagem é enviada ou recebida em uma conversa ativa. Isso inclui tanto mensagens do lead (user) quanto respostas da IA ou atendente (assistant).
Mensagens de sistema (funções internas, logs) não são enviadas por este webhook — apenas mensagens visíveis de user e assistant.

Payload

{
  "message": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "actor": "user",
    "type": "text",
    "content": "Quero saber mais sobre o apartamento de 3 quartos",
    "timestamp": "2026-05-13T18:25:00.000Z"
  },
  "person": {
    "id": "c3d4e5f6-7890-12ab-cdef-3456789012cd",
    "name": "Maria Oliveira",
    "email": "maria@email.com",
    "phone": "5521988888888"
  },
  "deal": {
    "id": "b2c3d4e5-6789-01ab-cdef-2345678901bc",
    "status": "active",
    "productProps": {
      "bedrooms": 3
    }
  },
  "source": {
    "id": "e5f6a7b8-9012-34ab-cdef-5678901234ef",
    "code": "whatsapp",
    "name": "WhatsApp - Site"
  },
  "metadata": {
    "timestamp": "2026-05-13T18:25:01.000Z",
    "eventType": "message"
  }
}

Campos

message

CampoTipoDescrição
message.idstringID único da mensagem
message.actorstringAutor da mensagem: user (lead/cliente) ou assistant (IA/atendente)
message.typestringTipo do conteúdo: text, image, document, audio, video
message.contentstringConteúdo textual da mensagem
message.timestampstringData/hora da mensagem (ISO 8601)
message.errorDetailsobject | undefinedPresente apenas quando a mensagem falhou no envio (ver abaixo)

person

CampoTipoDescrição
person.idstringID único do contato
person.namestring | nullNome completo
person.emailstring | nullE-mail
person.phonestring | nullTelefone com DDI (ex: 5521988888888)

deal

O campo deal pode ser undefined em cenários raros onde a mensagem não está vinculada a um deal.
CampoTipoDescrição
deal.idstringID do deal associado
deal.statusstring | nullStatus: active, won, lost
deal.productPropsobject | nullPropriedades do produto vinculado ao deal

source

CampoTipoDescrição
source.idstringID da origem
source.codestringCódigo da origem (ex: whatsapp, instagram, web)
source.namestringNome descritivo da origem

metadata

CampoTipoDescrição
metadata.timestampstringData/hora do envio do webhook (ISO 8601)
metadata.eventTypestringSempre "message"

Payload com erro

Quando uma mensagem falha no envio (ex: erro do provedor, rate limit), o campo errorDetails é incluído:
{
  "message": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "actor": "assistant",
    "type": "text",
    "content": "",
    "timestamp": "2026-05-13T18:25:00.000Z",
    "errorDetails": {
      "message": "Rate limit exceeded | 429 Too Many Requests",
      "code": "rate_limit"
    }
  },
  "person": {
    "id": "c3d4e5f6-7890-12ab-cdef-3456789012cd",
    "name": "Maria Oliveira",
    "email": "maria@email.com",
    "phone": "5521988888888"
  },
  "metadata": {
    "timestamp": "2026-05-13T18:25:01.000Z",
    "eventType": "message"
  }
}
CampoTipoDescrição
errorDetails.messagestring | undefinedDescrição do erro
errorDetails.codestring | undefinedCódigo do erro retornado pelo provedor

Exemplo de uso

app.post("/webhook/morada", (req, res) => {
  const { message, person, deal } = req.body;

  if (message.errorDetails) {
    console.error(`Erro na mensagem ${message.id}: ${message.errorDetails.message}`);
    // Alertar equipe sobre falha de envio
  } else {
    console.log(`[${message.actor}] ${person.name}: ${message.content}`);
    // Salvar mensagem no seu sistema
  }

  res.status(200).json({ received: true });
});

Resposta esperada

Retorne um status HTTP 200 para confirmar o recebimento:
{
  "received": true
}
Se o seu endpoint retornar um status diferente de 2xx ou não responder dentro do timeout, a Morada.ai poderá tentar reenviar o evento. Implemente idempotência para lidar com entregas duplicadas.