Webhooks

Webhooks

O Gemlead envia uma requisição HTTPS assinada ao seu servidor no momento em que um lead é encontrado, fica quente, responde ou reage à sua mensagem, ou quando o Sam AI tem uma resposta pronta, envia uma resposta ou passa uma conversa para você. A assinatura prova que ela vem da gente.

Configurar um endpoint

Adicione um endpoint no app, em API, ou com Criar um endpoint de webhook. Informe uma URL HTTPS pública e os tipos de evento que você quer, e guarde o secret retornado para verificar as assinaturas.

  • Só HTTPS, sem credenciais na URL e sem endereço privado, de loopback ou link local.
  • Até 10 endpoints por conta.
  • filters.persona_ids limita os eventos que um endpoint recebe aos leads de certas personas, seja qual for o tipo.
  • Envie um evento de teste para conferir seu servidor antes que os eventos reais cheguem.

Os webhooks vêm com os planos Business e Enterprise. Se a conta passar para o Free ou o Starter, os endpoints continuam lá, mas não enviam nada até ela voltar para Business ou Enterprise.

POST/v1/webhook_endpoints
curl -X POST https://gemlead.ai/api/v1/webhook_endpoints \
  -H "Authorization: Bearer $GEMLEAD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/gemlead",
    "events": ["lead.hot", "reply.received"],
    "description": "CRM sync",
    "filters": {
      "persona_ids": ["lvWBPnytpS"]
    }
  }'

Tipos de evento

Todo evento tem o mesmo envelope. O data dele depende do type.

TipoEnviado quando
lead.createdO Gemlead encontra e pontua um novo lead, seja qual for o score. Cada lead dispara o evento uma vez só, com o primeiro score, e apenas até 3 dias depois de ser encontrado, então repontuar um lead mais antigo nunca o dispara. Um lead que já recebe 60 ou mais de cara dispara também lead.hot.
lead.hotO score de um lead chega a 60 ou mais pela primeira vez. Cada lead dispara o evento uma vez só, e repontuar o lead nunca o dispara de novo.
reply.receivedUm lead envia uma nova mensagem para você, numa campanha ou não. Cada mensagem dispara o evento uma vez, se tiver menos de 6 horas. Quando muitas mensagens do lead chegam ao mesmo tempo, só as 5 mais recentes disparam o evento.
reaction.receivedUm lead reage a uma das suas mensagens com um emoji. Cada emoji do lead numa mensagem dispara o evento uma vez.
sam.suggestion.readyO Sam AI tem uma nova resposta pronta para você enviar, numa conversa no modo draft. Cada sugestão dispara o evento uma vez, se tiver menos de 6 horas.
sam.reply.sentUma resposta do Sam AI sai pela sua conta do X, sozinha no modo auto ou depois que você a aprova no app. Cada resposta dispara o evento uma vez, se tiver menos de 6 horas. As mensagens que você mesmo escreve nunca disparam o evento, elas aparecem em Obter uma conversa.
sam.handoffO Sam AI passa uma conversa para você quando não vê uma boa resposta sem a sua ajuda, quando o lead mandou só uma foto ou uma mensagem de voz, ou quando a resposta dele não conseguiu sair. No modo auto, ele então deixa as próximas mensagens do lead com você. Cada repasse dispara o evento uma vez, se tiver menos de 6 horas.

O objeto event

  • idstring
    Identificador único do evento, evt_ seguido de 24 caracteres. Também vem no cabeçalho Gemlead-Event-Id.
  • objectstring
    Sempre event.
  • typestring
    O tipo do evento.
    lead.createdlead.hotreply.receivedreaction.receivedsam.suggestion.readysam.reply.sentsam.handoff
  • created_atstring
    Quando o evento aconteceu, em ISO 8601.
  • account_idstring
    A conta do Gemlead em que ele aconteceu.
  • dataobject
    O conteúdo do evento, que depende do tipo.

lead.created

O Gemlead encontra e pontua um novo lead, seja qual for o score. Cada lead dispara o evento uma vez só, com o primeiro score, e apenas até 3 dias depois de ser encontrado, então repontuar um lead mais antigo nunca o dispara. Um lead que já recebe 60 ou mais de cara dispara também lead.hot.

Dados

lead.created
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "lead.created",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "object": {
      "id": "k3VnQ8wZpR",
      "object": "lead",
      "profile": {
        "x_user_id": "1592047713",
        "username": "mark_picks",
        "name": "Mark Ellis",
        "bio": "Free NBA picks every day. Sports fan first.",
        "followers_count": 2150,
        "following_count": 940,
        "location": "Denver, CO",
        "website": "https://markpicks.net",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1592047713/mark_400x400.jpg",
        "verified": false,
        "url": "https://x.com/mark_picks"
      },
      "score": 38,
      "score_reason": "Shares free picks for fun and sells nothing yet, no sign of a paying community.",
      "hot": false,
      "status": "scored",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": null,
      "conversation_id": null,
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    }
  }
}

lead.hot

O score de um lead chega a 60 ou mais pela primeira vez. Cada lead dispara o evento uma vez só, e repontuar o lead nunca o dispara de novo.

Dados

lead.hot
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "lead.hot",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "object": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "scored",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": null,
      "conversation_id": null,
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    }
  }
}

reply.received

Um lead envia uma nova mensagem para você, numa campanha ou não. Cada mensagem dispara o evento uma vez, se tiver menos de 6 horas. Quando muitas mensagens do lead chegam ao mesmo tempo, só as 5 mais recentes disparam o evento.

Dados

  • leadobject
    O lead que escreveu.
  • messageobject
    A nova mensagem, com direction igual a inbound.
  • campaignobject ou null
    A campanha em que o lead está, com id, name e status.
  • conversation_idstring
    Use com Obter uma conversa para ver o histórico completo.
reply.received
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "reply.received",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "lead": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "in_conversation",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": {
        "id": "c7RkQ2wLxe",
        "name": "Tipsters warm intro",
        "status": "in_progress"
      },
      "conversation_id": "msgOtJ8dvT",
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    },
    "message": {
      "id": "1985321409876543210",
      "object": "message",
      "direction": "inbound",
      "text": "Yes, I want to charge for my Discord. How does it work?",
      "created_at": "2026-11-06T08:12:44.000Z",
      "media": [],
      "reactions": [],
      "encrypted": false,
      "reply_to_message_id": null
    },
    "campaign": {
      "id": "c7RkQ2wLxe",
      "name": "Tipsters warm intro",
      "status": "in_progress"
    },
    "conversation_id": "msgOtJ8dvT"
  }
}

reaction.received

Um lead reage a uma das suas mensagens com um emoji. Cada emoji do lead numa mensagem dispara o evento uma vez.

Dados

  • leadobject
    O lead que reagiu.
  • messageobject
    A sua mensagem que recebeu a reação do lead, com direction igual a outbound.
  • reactionobject
    A nova reação, com direction igual a inbound.
reaction.received
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "reaction.received",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "lead": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "in_conversation",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": {
        "id": "c7RkQ2wLxe",
        "name": "Tipsters warm intro",
        "status": "in_progress"
      },
      "conversation_id": "msgOtJ8dvT",
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    },
    "message": {
      "id": "1985329981234567890",
      "object": "message",
      "direction": "outbound",
      "text": "Happy to show you. Do you sell picks monthly or per event?",
      "created_at": "2026-11-06T08:20:03.000Z",
      "media": [],
      "reactions": [
        {
          "emoji": "👍",
          "direction": "inbound",
          "created_at": "2026-11-06T08:24:51.000Z"
        }
      ],
      "encrypted": false,
      "reply_to_message_id": "1985321409876543210"
    },
    "reaction": {
      "emoji": "👍",
      "direction": "inbound",
      "created_at": "2026-11-06T08:24:51.000Z"
    }
  }
}

sam.suggestion.ready

O Sam AI tem uma nova resposta pronta para você enviar, numa conversa no modo draft. Cada sugestão dispara o evento uma vez, se tiver menos de 6 horas.

Dados

  • leadobject
    O lead a quem o Sam AI responde.
  • conversation_idstring
    Use com Obter o Sam AI de uma conversa para ler a sugestão de novo ou mudar o modo.
  • campaignobject ou null
    A campanha em que o lead está, com id, name e status.
  • suggestionobject
    A resposta que o Sam AI tem pronta.
sam.suggestion.ready
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "sam.suggestion.ready",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "lead": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "in_conversation",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": {
        "id": "c7RkQ2wLxe",
        "name": "Tipsters warm intro",
        "status": "in_progress"
      },
      "conversation_id": "msgOtJ8dvT",
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    },
    "conversation_id": "msgOtJ8dvT",
    "campaign": {
      "id": "c7RkQ2wLxe",
      "name": "Tipsters warm intro",
      "status": "in_progress"
    },
    "suggestion": {
      "messages": [
        "It takes two minutes. You set a price, members pay, and they get their Discord role right away.",
        "Want the link to set it up?"
      ],
      "stage": "answer_question",
      "why": "She asked how it works, so the reply explains it in one line and offers the link.",
      "replying_to_message_id": "1985321409876543210",
      "created_at": "2026-11-06T08:13:20.000Z"
    }
  }
}

sam.reply.sent

Uma resposta do Sam AI sai pela sua conta do X, sozinha no modo auto ou depois que você a aprova no app. Cada resposta dispara o evento uma vez, se tiver menos de 6 horas. As mensagens que você mesmo escreve nunca disparam o evento, elas aparecem em Obter uma conversa.

Dados

  • leadobject
    O lead a quem o Sam AI respondeu.
  • conversation_idstring
    Use com Obter uma conversa para ver o histórico completo.
  • campaignobject ou null
    A campanha em que o lead está, com id, name e status.
  • messagesarray de strings
    As DMs que o Sam AI enviou, em ordem.
  • sent_bystring
    auto quando o Sam AI enviou sozinho, approved quando você aprovou no app.
    autoapproved
  • replying_to_message_idstring ou null
    A mensagem do lead que ela respondeu.
  • sent_atstring
    Quando ela foi enviada, em ISO 8601.
sam.reply.sent
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "sam.reply.sent",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "lead": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "in_conversation",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": {
        "id": "c7RkQ2wLxe",
        "name": "Tipsters warm intro",
        "status": "in_progress"
      },
      "conversation_id": "msgOtJ8dvT",
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    },
    "conversation_id": "msgOtJ8dvT",
    "campaign": {
      "id": "c7RkQ2wLxe",
      "name": "Tipsters warm intro",
      "status": "in_progress"
    },
    "messages": [
      "It takes two minutes. You set a price, members pay, and they get their Discord role right away.",
      "Want the link to set it up?"
    ],
    "sent_by": "auto",
    "replying_to_message_id": "1985321409876543210",
    "sent_at": "2026-11-06T08:14:05.000Z"
  }
}

sam.handoff

O Sam AI passa uma conversa para você quando não vê uma boa resposta sem a sua ajuda, quando o lead mandou só uma foto ou uma mensagem de voz, ou quando a resposta dele não conseguiu sair. No modo auto, ele então deixa as próximas mensagens do lead com você. Cada repasse dispara o evento uma vez, se tiver menos de 6 horas.

Dados

  • leadobject
    O lead a responder.
  • conversation_idstring
    Use com Obter uma conversa para ver o histórico completo.
  • campaignobject ou null
    A campanha em que o lead está, com id, name e status.
  • reasonstring ou null
    Por que o Sam AI passa a conversa para você, nas palavras dele.
sam.handoff
{
  "id": "evt_8kQ2vXr4LmT9wPz1Hc6YbN3d",
  "object": "event",
  "type": "sam.handoff",
  "created_at": "2026-11-05T14:03:40.117Z",
  "account_id": "a9PzK2vRtM",
  "data": {
    "lead": {
      "id": "msgOtJ8dvT",
      "object": "lead",
      "profile": {
        "x_user_id": "1460283925",
        "username": "jane_builds",
        "name": "Jane Doe",
        "bio": "Runs a paid trading community. Daily setups, no hype.",
        "followers_count": 12400,
        "following_count": 380,
        "location": "Austin, TX",
        "website": "https://janedoe.com",
        "profile_image_url": "https://pbs.twimg.com/profile_images/1460283925/jane_400x400.jpg",
        "verified": true,
        "url": "https://x.com/jane_builds"
      },
      "score": 86,
      "score_reason": "Runs a paid trading community and asks how to collect payments for it.",
      "hot": true,
      "status": "in_conversation",
      "persona": {
        "id": "lvWBPnytpS",
        "name": "Tipsters"
      },
      "campaign": {
        "id": "c7RkQ2wLxe",
        "name": "Tipsters warm intro",
        "status": "in_progress"
      },
      "conversation_id": "msgOtJ8dvT",
      "locked_to": null,
      "found_at": "2026-11-05T14:02:11.482Z",
      "scored_at": "2026-11-05T14:03:40.117Z",
      "updated_at": "2026-11-05T14:03:40.117Z",
      "metadata": {}
    },
    "conversation_id": "msgOtJ8dvT",
    "campaign": {
      "id": "c7RkQ2wLxe",
      "name": "Tipsters warm intro",
      "status": "in_progress"
    },
    "reason": "She wants a call before she signs up."
  }
}

Envio

O Gemlead envia cada evento como um POST em JSON e espera 10 segundos pela sua resposta. Qualquer 2xx conta como entregue. Um redirecionamento, qualquer outro status, um timeout ou um erro de conexão conta como falha, e o evento é enviado de novo.

CabeçalhoValor
Gemlead-SignatureO timestamp e a assinatura, t=1762444800,v1=5f2b...
Gemlead-Event-IdO id do evento, para pular eventos que você já tratou.
Gemlead-Event-TypeO type do evento.
User-AgentGemlead-Webhooks/1.0
Requisição
POST /webhooks/gemlead HTTP/1.1
Content-Type: application/json; charset=utf-8
User-Agent: Gemlead-Webhooks/1.0
Gemlead-Event-Id: evt_8kQ2vXr4LmT9wPz1Hc6YbN3d
Gemlead-Event-Type: lead.hot
Gemlead-Signature: t=1762444800,v1=58ca5e964b92d617c979d3f067cdc2035a1a1a9d3f848d7d927c2db09b8e9baa

Verificar assinaturas

Qualquer pessoa pode enviar uma requisição para a sua URL. Confira se cada uma vem do Gemlead antes de confiar nela.

  1. Leia o corpo bruto como bytes, antes de qualquer parsing de JSON. Fazer o parsing e reescrever o corpo muda os bytes.
  2. Divida o cabeçalho Gemlead-Signature nas vírgulas. t é um timestamp Unix em segundos, v1 é a assinatura.
  3. Calcule o HMAC SHA256 de t, um ponto e o corpo bruto, usando como chave o segredo inteiro do endpoint, whsec_ incluído, e codifique o resultado em hexadecimal.
  4. Compare o resultado com cada v1 em tempo constante.
  5. Recuse um t com mais de 5 minutos de diferença do seu relógio, para que uma requisição antiga não possa ser reenviada. Cada nova tentativa é assinada com um t novo.

Responda 400 quando a verificação falhar. Guarde o segredo numa variável de ambiente como GEMLEAD_WEBHOOK_SECRET.

const crypto = require("crypto");
const express = require("express");

// rawBody: the request body exactly as received, before any JSON parsing.
function verifyGemleadSignature(rawBody, header, secret, toleranceSeconds = 300) {
  if (typeof header !== "string") return false;
  let timestamp = null;
  const signatures = [];
  for (const part of header.split(",")) {
    const [key, value] = part.split("=", 2).map((s) => (s || "").trim());
    if (key === "t") timestamp = value;
    if (key === "v1" && value) signatures.push(value);
  }
  if (!/^\d+$/.test(timestamp || "") || signatures.length === 0) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest();
  return signatures.some((signature) => {
    const given = Buffer.from(signature, "hex");
    return given.length === expected.length && crypto.timingSafeEqual(given, expected);
  });
}

const app = express();

// The body must stay raw on this route.
app.post("/webhooks/gemlead", express.raw({ type: "application/json" }), (req, res) => {
  const ok = verifyGemleadSignature(
    req.body,
    req.get("Gemlead-Signature"),
    process.env.GEMLEAD_WEBHOOK_SECRET,
  );
  if (!ok) return res.status(400).send("Invalid signature");

  const event = JSON.parse(req.body.toString("utf8"));
  // Already handled? Skip it, retries send the same event.id again.
  if (event.type === "lead.created") {
    // event.data.object is the new lead, hot or not
  } else if (event.type === "lead.hot") {
    // event.data.object is the lead
  } else if (event.type === "reply.received") {
    // event.data.lead, event.data.message, event.data.campaign, event.data.conversation_id
  }
  res.sendStatus(200);
});

app.listen(3000);

Novas tentativas

Quando um envio falha, o Gemlead tenta de novo 7 vezes, com uma espera maior a cada vez. Depois da 8ª tentativa, cerca de 45 horas após a primeira, o envio é marcado como falha.

TentativaEnviada
1Na hora
21 minuto após a falha anterior
35 minutos após a falha anterior
430 minutos após a falha anterior
52 horas após a falha anterior
66 horas após a falha anterior
712 horas após a falha anterior
824 horas após a falha anterior

Um endpoint que falha por 3 dias seguidos, com pelo menos 8 tentativas com falha, é desativado. O status dele passa a disabled, o disabled_reason a failing, e os envios ainda pendentes terminam como falha. Corrija seu servidor e depois reative o endpoint no app ou com Atualizar um endpoint de webhook, o que zera a contagem. Os eventos de teste são enviados uma vez só e nunca entram nessa contagem.

Listar envios mostra o código de status e o erro de cada tentativa, para você ver o que seu servidor respondeu.

Boas práticas

  • Responda 2xx em até 10 segundos e depois faça o trabalho numa fila.
  • Cada evento é entregue pelo menos uma vez. Use o id do evento, também em Gemlead-Event-Id, para pular um evento que você já tratou.
  • Os eventos podem chegar fora de ordem. Compare created_at, ou busque o lead de novo para ter o estado mais recente.
  • Verifique toda assinatura e recuse timestamps antigos.
  • Renovar o segredo substitui o atual na hora. Faça o deploy do novo logo em seguida. Os envios que falharem nesse meio-tempo são repetidos e assinados com ele.
  • Eventos e envios ficam guardados por 30 dias.