API e webhooks
Resumo
A API devolve os mesmos leads do feed, em JSON, para o seu CRM ou sistema. Chave Bearer, 60 chamadas por minuto, plano Equipe. A referência completa, com todos os campos, está no OpenAPI interativo.
Visão geral
Endereço base: https://api-leads.pervian.tech/v1. Tudo é JSON em UTF-8, datas em ISO 8601 e CNPJ com 14 dígitos, com ou sem pontuação. A lista de gatilhos, com os ids, sai de GET /api/catalogo.
O contato segue a mesma regra do app: vem mascarado até a sua conta revelar. Revelar custa 1 crédito na primeira vez, e o crédito é o mesmo do app, da exportação e do lote.
Autenticação
Crie a chave dentro do app, na área de chaves de API (plano Equipe). Ela começa com rdr_ e aparece uma vez só. Guardamos apenas o hash. Para revogar, apague a chave: ela para na hora.
export RADAR_CHAVE=rdr_…
curl -s -H "Authorization: Bearer $RADAR_CHAVE" https://api-leads.pervian.tech/v1/creditosLimites e erros
60 requisições por minuto por chave. Passou disso, a resposta é 429 com o cabeçalho Retry-After em segundos. Erros vêm sempre como {"erro": "<código>", "mensagem": "<texto>"}.
| Status | erro | Quando |
|---|---|---|
| 401 | nao_autenticado | Sem chave, chave errada ou revogada |
| 402 | plano | A conta saiu do plano Equipe |
| 402 | creditos | Sem crédito para revelar; traz necessarios e saldo |
| 404 | nao_encontrado | CNPJ fora das empresas ativas |
| 404 | sem_contato | Empresa sem contato público ou que pediu remoção; nenhum crédito usado |
| 422 | validacao | Parâmetro inválido; traz detalhes por campo |
| 429 | limite_de_requisicoes | Mais de 60 chamadas no minuto |
GET /v1/gatilhos
Leads por gatilho, do evento mais recente para o mais antigo, 50 por página, sem contato (só se existe telefone, WhatsApp e e-mail). Parâmetros: tipo, uf, municipio (código da Receita), desde (AAAA-MM-DD) e pagina (1 a 20).
curl -s -H "Authorization: Bearer $RADAR_CHAVE" \
"https://api-leads.pervian.tech/v1/gatilhos?tipo=empresa_aberta&uf=SP&desde=2026-10-01"{
"dados": [{
"gatilho": {"tipo": "empresa_aberta", "nome": "Empresa aberta este mês",
"motivo": "Acabou de abrir e ainda não tem fornecedor",
"fonte": "Receita Federal (CNPJ)", "data_evento": "2026-10-20"},
"empresa": {"cnpj": "12345678000100", "nome_fantasia": "DOCES DA VILA",
"municipio_nome": "CAMPINAS", "uf": "SP"},
"score": 67,
"contato": {"tem_telefone": true, "tem_email": true,
"tem_whatsapp": true, "revelado": false}
}],
"pagina": 1, "por_pagina": 50, "tem_mais": false
}GET /v1/empresas/{cnpj}
Dados cadastrais, até 50 gatilhos (o mais novo primeiro) e o contato: mascarado se a conta ainda não revelou, completo se já revelou, null se a empresa pediu remoção.
curl -s -H "Authorization: Bearer $RADAR_CHAVE" https://api-leads.pervian.tech/v1/empresas/12345678000100POST /v1/empresas/{cnpj}/contato
Revela o contato. Custa 1 crédito na primeira vez para a conta; depois, consumidos: 0. O campo finalidade (10 a 300 caracteres) é obrigatório e fica registrado na trilha de finalidade, como pede a LGPD.
curl -s -X POST -H "Authorization: Bearer $RADAR_CHAVE" \
-H "Content-Type: application/json" \
-d '{"finalidade": "Oferta de serviço contábil para empresa recém-aberta"}' \
https://api-leads.pervian.tech/v1/empresas/12345678000100/contato{
"contato": {"revelado": true,
"telefones": [{"numero": "(19) 0000-0000",
"whatsapp": "https://wa.me/551900000000"}],
"email": "contato@docesdavila.example"},
"consumidos": 1,
"saldo": {"total": 2499, "franquia": 2499, "extras": 0}
}GET /v1/creditos
curl -s -H "Authorization: Bearer $RADAR_CHAVE" https://api-leads.pervian.tech/v1/creditos
{"total": 2500, "franquia": 2500, "extras": 0}Webhooks
Na área de integrações do app, cadastre uma URL https:// pública. O Radar faz um POST com JSON a cada lead enviado à mão, a cada lead novo com score acima do mínimo que você escolher e a cada gatilho novo em empresa da sua watchlist. O segredo de assinatura aparece uma vez, na criação.
| Cabeçalho | Valor |
|---|---|
| X-Radar-Evento | lead.enviado, lead.novo, watchlist.gatilho ou teste |
| X-Radar-Assinatura | sha256= seguido do HMAC-SHA256 do corpo bruto, em hexadecimal, com o seu segredo |
| Content-Type | application/json |
Até 3 tentativas, com espera de 2 e 8 segundos, em erro de conexão, 5xx ou 429. Outros 4xx não são repetidos e redirecionamentos não são seguidos. O contato só vai no corpo se a sua conta já revelou; senão, contato é null.
{
"evento": "lead.novo",
"enviado_em": "2026-10-24T02:02:23+00:00",
"empresa": {"cnpj": "12345678000100", "nome_fantasia": "DOCES DA VILA", "uf": "SP"},
"gatilho": {"tipo": "empresa_aberta", "data_evento": "2026-10-20",
"motivo": "Acabou de abrir e ainda não tem fornecedor"},
"score": 82,
"contato": null,
"link": "…/app/empresa/12345678000100"
}Conferir a assinatura
Calcule o HMAC sobre o corpo exatamente como chegou, antes de converter o JSON, e compare em tempo constante.
import hashlib, hmac
esperado = "sha256=" + hmac.new(SEGREDO.encode(), corpo_bruto, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(esperado, request.headers["X-Radar-Assinatura"])import { createHmac, timingSafeEqual } from 'node:crypto'
const esperado = 'sha256=' + createHmac('sha256', SEGREDO).update(corpoBruto).digest('hex')
const recebido = req.headers['x-radar-assinatura'] ?? ''
const ok = esperado.length === recebido.length &&
timingSafeEqual(Buffer.from(esperado), Buffer.from(recebido))Dúvidas sobre planos: Preços. A API e o webhook entram no plano Equipe.