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.
| Campo | Tipo | Descrição |
|---|---|---|
x-api-keyobrigatório | string | Identifica a sua empresa na Ledio. Fica visível no painel e pode ser copiada de lá. |
x-webhook-secretobrigatório | string | Segredo 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. |
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).
{
"success": true,
"message": "Welcome message sent",
"contactId": "1f5c2a10-2b3c-4d5e-6f70-8a9b0c1d2e3f"
}| Campo | Tipo | Descrição |
|---|---|---|
success | boolean | Se a ação foi concluída. |
message | string | Detalhe do que aconteceu — ou o motivo, quando success é false. |
contactId | string | Id do contato na Ledio, quando a ação envolveu um. Guarde para correlacionar com o seu sistema. |
1. Novo cadastro
/webhook/external/new-userAvisa 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.
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | string | Telefone com DDI, só números: 5511999999999. Sem espaços, parênteses ou traços. |
name | string | Nome da pessoa. O agente usa para personalizar o atendimento. |
externalId | string | O id dela no seu sistema. Serve para você correlacionar os dois lados depois. |
flow | CONVERSION | SUPPORT | ONBOARDING | BILLING | FEEDBACK | CUSTOM | Como o agente deve abordar. Padrão CONVERSION (foco em venda). |
context | objeto | Dados livres que o agente passa a conhecer durante a conversa — origem, campanha, plano pretendido. |
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
/webhook/external/user-convertedAvisa 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.
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | string | O mesmo telefone usado no cadastro. |
name | string | Atualiza o nome do contato, se já existir. |
externalId | string | Id da pessoa no seu sistema. |
context | objeto | O que ela comprou, para o agente ter contexto: { "plan": "pro", "value": 2990, "currency": "BRL" }. |
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
/webhook/external/change-flowMuda 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.
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | string | Telefone do contato. |
flowobrigatório | CONVERSION | SUPPORT | ONBOARDING | BILLING | FEEDBACK | CUSTOM | O novo fluxo. |
context | objeto | Motivo da mudança: { "reason": "user_requested_support", "ticket_id": "TK-123" }. |
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
/webhook/external/send-messageEnvia um texto pelo WhatsApp para um contato que já conversou com você.
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | string | Telefone de um contato que já existe. |
message | string | O texto a enviar. |
context | string | Informação para o agente considerar daqui em diante. Ex.: "Lead veio do Instagram, interessado em SUV 2024". |
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)
/webhook/external/otpEnvia um código de verificação pelo WhatsApp usando um template de autenticação aprovado pela Meta.
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | string | Telefone de destino. |
codeobrigatório | string | O código gerado por você. A Ledio apenas entrega, não gera nem valida. |
expiresInMinutesobrigatório | number | Quantos minutos o código vale, exibido na mensagem. |
name | string | Nome do destinatário. |
externalId | string | Id da pessoa no seu sistema. |
brand | string | Nome da marca exibido na mensagem. |
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.
| Campo | Tipo | Descrição |
|---|---|---|
contact.created | evento | Um contato novo entrou em conversa. |
contact.converted | evento | Um contato foi marcado como cliente — pelo agente, pelo painel ou pelo endpoint de conversão. |
Todos os eventos chegam no mesmo envelope:
{
"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"
}
}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.
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
| Campo | Tipo | Descrição |
|---|---|---|
401 | autenticação | Cabeçalho faltando, API key desconhecida ou segredo incorreto. A mensagem diz qual dos casos. |
400 | validação | Corpo inválido — campo obrigatório ausente ou fluxo com valor fora da lista. |
200 com success: false | regra de negócio | Autenticado, 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.