API e Integrações

Última atualização: 14 de agosto de 2026

O que dá para fazer

A Ledio se integra ao seu sistema nos dois sentidos. Você avisa a Ledio quando algo acontece do seu lado (alguém se cadastrou, alguém comprou) e a Ledio avisa você quando algo acontece na conversa (um contato novo apareceu, um contato virou cliente).

Todos os endpoints partem de https://api.ledio.ai e recebem e devolvem JSON.

Autenticação

Toda chamada precisa de dois cabeçalhos. Os dois são gerados no painel, em Configurações → API e Webhooks.

CampoTipoDescrição
x-api-keyobrigatóriostringIdentifica a sua empresa na Ledio. Fica visível no painel e pode ser copiada de lá.
x-webhook-secretobrigatóriostringSegredo da integração, começa com whsec_. É mostrado uma única vez no momento em que você gera. A Ledio guarda apenas um hash, então não há como recuperá-lo depois: se perder, gere outro.
Esses cabeçalhos valem por qualquer requisição em nome da sua empresa. Mantenha-os no servidor. Nunca coloque em código de frontend, app mobile ou repositório público — quem tiver os dois pode enviar mensagens pelo seu WhatsApp.

Faltando ou errado, a resposta é 401 com uma mensagem dizendo qual dos dois falhou.

Resposta padrão

Os endpoints respondem 200 com o mesmo formato. Confira sempre o campo success: um 200 com success: false significa que autenticamos você, mas a ação não aconteceu (número inexistente no WhatsApp, contato não encontrado, canal desconectado).

resposta
{
  "success": true,
  "message": "Welcome message sent",
  "contactId": "1f5c2a10-2b3c-4d5e-6f70-8a9b0c1d2e3f"
}
CampoTipoDescrição
successbooleanSe a ação foi concluída.
messagestringDetalhe do que aconteceu — ou o motivo, quando success é false.
contactIdstringId do contato na Ledio, quando a ação envolveu um. Guarde para correlacionar com o seu sistema.

1. Novo cadastro

POST/webhook/external/new-user

Avisa que alguém se cadastrou no seu sistema. A Ledio cria o contato, confere se o número existe no WhatsApp e, existindo, o agente de IA inicia a conversa no fluxo escolhido.

CampoTipoDescrição
phoneobrigatóriostringTelefone com DDI, só números: 5511999999999. Sem espaços, parênteses ou traços.
namestringNome da pessoa. O agente usa para personalizar o atendimento.
externalIdstringO id dela no seu sistema. Serve para você correlacionar os dois lados depois.
flowCONVERSION | SUPPORT | ONBOARDING | BILLING | FEEDBACK | CUSTOMComo o agente deve abordar. Padrão CONVERSION (foco em venda).
contextobjetoDados livres que o agente passa a conhecer durante a conversa — origem, campanha, plano pretendido.
curl
curl -X POST https://api.ledio.ai/webhook/external/new-user \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_API_KEY" \
  -H "x-webhook-secret: whsec_SEU_SECRET" \
  -d '{
    "phone": "5511999999999",
    "name": "João Silva",
    "externalId": "usr_abc123",
    "flow": "CONVERSION",
    "context": { "source": "landing_page", "campaign": "black_friday" }
  }'

2. Usuário converteu

POST/webhook/external/user-converted

Avisa que a pessoa assinou ou comprou. O agente para de vender e passa a tratá-la como cliente. Mande isso assim que o pagamento confirmar: sem esse aviso, o agente continua oferecendo o que ela já comprou.

CampoTipoDescrição
phoneobrigatóriostringO mesmo telefone usado no cadastro.
namestringAtualiza o nome do contato, se já existir.
externalIdstringId da pessoa no seu sistema.
contextobjetoO que ela comprou, para o agente ter contexto: { "plan": "pro", "value": 2990, "currency": "BRL" }.
curl
curl -X POST https://api.ledio.ai/webhook/external/user-converted \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_API_KEY" \
  -H "x-webhook-secret: whsec_SEU_SECRET" \
  -d '{
    "phone": "5511999999999",
    "context": { "plan": "pro", "value": 2990, "currency": "BRL" }
  }'

3. Mudar o fluxo de atendimento

POST/webhook/external/change-flow

Muda como o agente se comporta com um contato que já existe. Útil quando a pessoa abre um chamado de suporte no seu sistema e você quer que a conversa no WhatsApp acompanhe.

CampoTipoDescrição
phoneobrigatóriostringTelefone do contato.
flowobrigatórioCONVERSION | SUPPORT | ONBOARDING | BILLING | FEEDBACK | CUSTOMO novo fluxo.
contextobjetoMotivo da mudança: { "reason": "user_requested_support", "ticket_id": "TK-123" }.
curl
curl -X POST https://api.ledio.ai/webhook/external/change-flow \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_API_KEY" \
  -H "x-webhook-secret: whsec_SEU_SECRET" \
  -d '{ "phone": "5511999999999", "flow": "SUPPORT" }'

4. Enviar mensagem

POST/webhook/external/send-message

Envia um texto pelo WhatsApp para um contato que já conversou com você.

Este endpoint não cria contato e não envia para quem nunca falou com você. É proteção deliberada: disparar para número frio é a forma mais rápida de ter o WhatsApp da sua empresa banido. Para iniciar uma conversa do zero, use o endpoint de novo cadastro.
CampoTipoDescrição
phoneobrigatóriostringTelefone de um contato que já existe.
messagestringO texto a enviar.
contextstringInformação para o agente considerar daqui em diante. Ex.: "Lead veio do Instagram, interessado em SUV 2024".
curl
curl -X POST https://api.ledio.ai/webhook/external/send-message \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_API_KEY" \
  -H "x-webhook-secret: whsec_SEU_SECRET" \
  -d '{
    "phone": "5511999999999",
    "message": "Oi! Posso te ajudar?"
  }'

5. Código de verificação (OTP)

POST/webhook/external/otp

Envia um código de verificação pelo WhatsApp usando um template de autenticação aprovado pela Meta.

Requer que a sua empresa esteja na Cloud API da Meta e tenha um template de autenticação aprovado. Se você usa a conexão por QR Code, este endpoint não funciona. Fale com o suporte antes de integrar.
CampoTipoDescrição
phoneobrigatóriostringTelefone de destino.
codeobrigatóriostringO código gerado por você. A Ledio apenas entrega, não gera nem valida.
expiresInMinutesobrigatórionumberQuantos minutos o código vale, exibido na mensagem.
namestringNome do destinatário.
externalIdstringId da pessoa no seu sistema.
brandstringNome da marca exibido na mensagem.
curl
curl -X POST https://api.ledio.ai/webhook/external/otp \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_API_KEY" \
  -H "x-webhook-secret: whsec_SEU_SECRET" \
  -d '{
    "phone": "5511999999999",
    "code": "123456",
    "expiresInMinutes": 5
  }'

Receber eventos da Ledio

O caminho inverso. Cadastre uma URL em Configurações → API e Webhooks e a Ledio envia um POST para ela quando algo acontece na conversa.

CampoTipoDescrição
contact.createdeventoUm contato novo entrou em conversa.
contact.convertedeventoUm contato foi marcado como cliente, pelo agente, pelo painel ou pelo endpoint de conversão.
contact.updatedeventoO agente reclassificou o interesse do contato (engagement) ou descobriu o nome dele.

Todos os eventos chegam no mesmo envelope:

corpo enviado por nós
{
  "id": "5f1c2a10-2b3c-4d5e-6f70-8a9b0c1d2e3f",
  "type": "contact.converted",
  "createdAt": "2026-08-14T18:22:05.412Z",
  "data": {
    "businessSlug": "sua-empresa",
    "contactId": "1f5c2a10-2b3c-4d5e-6f70-8a9b0c1d2e3f",
    "phone": "5511999999999",
    "name": "João Silva",
    "status": "CONVERTED",
    "flow": "ONBOARDING",
    "engagement": "HOT"
  }
}

Use o id para descartar repetições: em caso de falha na entrega a Ledio tenta de novo, então o mesmo evento pode chegar duas vezes. Trate o recebimento como idempotente.

Conferindo a assinatura

Cada requisição vai assinada no cabeçalho x-ledio-signature, no formato sha256=<hex>. É um HMAC-SHA256 do corpo exatamente como recebido, usando o segredo que você cadastrou.

Calcule o HMAC sobre o corpo cru, antes de qualquer parse. Se você serializar o JSON de novo para conferir, a assinatura não vai bater — é o erro mais comum nessa etapa.
Node.js
import crypto from 'node:crypto'

// rawBody = o corpo como string, sem parse
function assinaturaConfere(rawBody, header, segredo) {
  const esperado =
    'sha256=' +
    crypto.createHmac('sha256', segredo).update(rawBody).digest('hex')

  const a = Buffer.from(esperado)
  const b = Buffer.from(header ?? '')
  // Comparação em tempo constante evita vazar a assinatura por timing
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Responda 2xx rápido. Se o seu endpoint demorar ou responder erro, a Ledio considera falha e tenta de novo mais tarde.

Erros

CampoTipoDescrição
401autenticaçãoCabeçalho faltando, API key desconhecida ou segredo incorreto. A mensagem diz qual dos casos.
400validaçãoCorpo inválido — campo obrigatório ausente ou fluxo com valor fora da lista.
200 com success: falseregra de negócioAutenticado, mas a ação não aconteceu. O motivo vem em message: número não existe no WhatsApp, contato não encontrado, canal desconectado.

Recomendações de integração

Guarde o contactId que volta na primeira chamada. Ele é a chave para correlacionar a conversa na Ledio com o registro no seu sistema, e evita depender do telefone, que muda.

Mande sempre o telefone no mesmo formato, com DDI e apenas números. A Ledio normaliza, mas manter o padrão de um lado só facilita a conferência quando algo não bate.

Trate success: false como resposta esperada, não como exceção. Número que não existe no WhatsApp é situação comum e não deveria quebrar a sua fila de processamento.

Precisa de ajuda?

Se algo aqui não bater com o que você está vendo na prática, fale com a gente pelo suporte no painel. Documentação divergente do comportamento é bug, e a gente quer saber.