Páginas da documentação

Desenvolvedores · Guia · v1.2.0

Recebendo webhooks

Os avisos que o seu sistema recebe, o corpo de cada um e como conferir a assinatura.

https://leadgo.com.br/api/v1 Baixar arquivo para IA OpenAPI 3.1 Criar token

Eventos

Cadastre a URL do seu sistema em POST /webhooks (ou no painel, em API) e receba um POST em JSON a cada evento. Responda 2xx em até 15 segundos; o processamento pesado deve ficar para depois da resposta.

Evento Quando Em data
campaign.published A campanha chegou à plataforma (em análise, ativa ou pausada). {campaign, previous_status}
campaign.failed A publicação falhou; o motivo vem em error.message. Corrija e use POST /campaigns/{id}/retry. {campaign, previous_status}
campaign.status_changed O status mudou depois de publicada (aprovada, pausada, reprovada, concluída, excluída na Meta...). {campaign, previous_status}
campaign.deleted A campanha foi excluída (pela API, pelo painel ou descartada). {campaign}
ad.approved Um anúncio passou na revisão da Meta (ou teve a reprovação revertida). {campaign_id, ad}
ad.rejected Um anúncio foi reprovado pela Meta; o motivo vem em rejection_reason. {campaign_id, ad}
alert.created Algo novo pede atenção na conta de anúncio: pagamento, problema de entrega, verba no limite ou gasto sem resultado. {alert}
ad_account.status_changed A situação da conta de anúncio mudou (ativa, restrita, desativada ou encerrada). {ad_account, previous_status, status}
lead.created Chegou um lead novo de um formulário instantâneo. {lead}
lead.status_changed O status de um lead mudou (contatado, qualificado, venda, perdido...), pela API ou pelo painel. {lead, previous_status}
lead.scored A IA deu a nota do lead (quente, morno ou frio) com o motivo e a mensagem sugerida. {lead}
brain.report_ready O Gestor IA terminou uma análise: aguardando aprovação, sem ação ou já executada no automático. {report} (com actions)
media.ready A mídia enviada por URL foi baixada e está pronta para os criativos. {media}
media.failed Não deu para baixar a mídia enviada por URL; o motivo vem em error. {media}
webhook.test Envio de teste (botão "Testar" ou POST /webhooks/{id}/test). {message}

Cada objeto em data vem no mesmo formato da rota GET correspondente (campaign como GET /campaigns/{id} sem os conjuntos, lead como GET /leads/{id} sem o histórico). Os eventos lead.* exigem que quem cadastra o webhook possa ver os leads, e brain.report_ready, que possa ver o Gestor IA.

Corpo de campaign.published
{
    "id": "evt_01jbz9a1c5f9j3m7q1t5x9b3e7",
    "type": "campaign.published",
    "api_version": "v1",
    "created_at": "2026-10-28T15:02:11+00:00",
    "account_id": "01jbw8r5x9a3d7g1k5n9s3w7b1",
    "data": {
        "campaign": {
            "id": "01jby0q4c8m2d6t9v3k7w5r1xa",
            "name": "Promoção de outubro",
            "goal": "traffic",
            "goal_label": "Tráfego",
            "status": "pending_review",
            "status_label": "Em análise",
            "created_via": "api",
            "budget": {
                "level": "campaign",
                "type": "daily",
                "amount_cents": 5000,
                "currency": "BRL"
            },
            "schedule": {
                "starts_at": "2026-10-28T03:00:00+00:00",
                "ends_at": null
            },
            "error": null,
            "platform": "meta",
            "platform_campaign_id": "120212345678900001",
            "published_at": "2026-10-28T15:02:11+00:00",
            "synced_at": "2026-10-28T15:40:00+00:00",
            "created_at": "2026-10-28T15:00:00+00:00",
            "updated_at": "2026-10-28T15:02:11+00:00",
            "links": {
                "panel": "https://app.leadgo.com.br/app/campaigns/01jby0q4c8m2d6t9v3k7w5r1xa"
            }
        },
        "previous_status": "creating"
    }
}

Conferindo a assinatura

Cada aviso traz X-Leadgo-Event, X-Leadgo-Event-Id (o mesmo em todas as tentativas), X-Leadgo-Timestamp e X-Leadgo-Signature. A assinatura é v1= seguido do HMAC-SHA256, em hexadecimal, de "{timestamp}.{corpo}" com o segredo do webhook. No seu receptor:

  • Leia o corpo cru, exatamente como chegou, antes de converter o JSON.
  • Calcule v1= + HMAC-SHA256 (hex) de "{X-Leadgo-Timestamp}.{corpo}" com o segredo do webhook.
  • Compare com X-Leadgo-Signature em tempo constante (hash_equals, crypto.timingSafeEqual, hmac.compare_digest).
  • Recuse avisos com mais de 5 minutos de diferença entre o timestamp e o seu relógio.
  • Descarte eventos repetidos pelo X-Leadgo-Event-Id.
Conferência no terminal (openssl)
# corpo.json: o corpo cru do aviso, byte a byte.
# TIMESTAMP e ASSINATURA: os cabeçalhos X-Leadgo-Timestamp e X-Leadgo-Signature.
ESPERADA="v1=$( { printf '%s.' "$TIMESTAMP"; cat corpo.json; } \
  | openssl dgst -sha256 -hmac "$LEADGO_WEBHOOK_SECRET" | sed 's/^.* //')"

[ "$ESPERADA" = "$ASSINATURA" ] && echo "assinatura válida" || echo "recusar"

Para testar o receptor, peça um aviso webhook.test assinado:

POST /webhooks/{id}/test
curl -X POST "https://leadgo.com.br/api/v1/webhooks/01jbz8e2h6k0n4r8u2x6b0f4jm/test" \
  -H "Authorization: Bearer $LEADGO_TOKEN" \
  -H "Accept: application/json"

Entregas e novas tentativas

  • Sem resposta 2xx, tentamos de novo depois de 1, 5, 15 e 60 minutos.
  • Depois de 10 avisos perdidos seguidos, o webhook é desligado e quem administra a API é avisado no painel.
  • Os avisos podem chegar fora de ordem: o corpo é uma foto do momento (veja previous_status). Na dúvida, consulte GET /campaigns/{id}.
  • O endereço precisa ser https público; não seguimos redirecionamentos.
  • Até 5 webhooks por conta.