Risco de IP e de e-mail
Risco de IP e de e-mail
Dois módulos avaliam o contexto da verificação, e não a identidade: Verificação de IP (ip_risk) e Risco de e-mail (email_risk). Nenhum dos dois pede passo novo ao usuário, e nenhum dos dois reprova sozinho: são portões suaves, como os módulos de canal. Um sinal aqui leva a verificação para review com a evidência no webhook, nunca a denied automático.
ip_risk não diz quem está por trás do IP, e email_risk não prova que a caixa é da pessoa (quem prova posse é a Validação de e-mail).Dois campos do payload merecem leitura antes de você programar contra ele. provider_verdict diz se a camada de reputação de rede/endereço estava disponível para aquela consulta: quando vem not_cached, os campos que dependem dela chegam null e isso significa não medido, jamais "limpo". No ip_risk existe ainda o network_measured: quando ele vem false, nenhuma camada de rede respondeu e o módulo sai pending em vez de dizer que está limpo (e nesse caso ele não é cobrado). E scope, no email_risk, diz o que foi de fato analisado: mailbox quando o flow também tem email_otp (é dele que o endereço vem, digitado pelo titular no widget) e domain quando só o domínio existia. No escopo domain, role_based e plus_alias vêm null: não havia caixa para olhar. Combine sempre email_risk com email_otp no mesmo flow: sem ele o endereço nunca chega ao produto (você não envia contato na criação), o módulo sai pending com reason: "email_not_provided", a verificação vai para revisão e o módulo não é cobrado.
O ip_risk devolve derivados do endereço, e não o endereço: país, ASN, organização do ASN e a classe da conexão. O IP, a cidade e a coordenada não trafegam. No email_risk vale a mesma regra dos módulos de canal: só o domínio, a máscara e o email_fp (o mesmo HMAC que a Validação de e-mail publica para o mesmo endereço, para você correlacionar sem receber o dado em claro).
No ip_risk, proxy e VPN saem separados porque a pergunta que você faz sobre cada um é diferente, e anonymizer é apenas o "ou" dos dois. Ao lado deles viaja o comportamento recente do endereço, como o fornecedor o declara: recent_abuse (houve abuso conhecido a partir dali), bot (tráfego automatizado) e abuse_velocity, um ordinal fechado em none, low, medium e high. Valor fora desse vocabulário vira null, nunca um veredito por acidente. E vale para todos eles a regra do provider_verdict: null significa que o fornecedor não respondeu sobre aquele ponto, jamais que respondeu que está limpo.
No email_risk, disposable_listed e forwarder_listed declaram de onde veio a afirmação: eles são a nossa lista curada de domínios descartáveis e de encaminhadores mascarados, que soma ao veredito do fornecedor em vez de substituí-lo. Assim disposable: true com disposable_listed: false quer dizer "quem afirmou foi o fornecedor", e a nossa lista, que é curta por desenho, não transforma o próprio false em "medimos e está limpo". Outros dois campos olham o formato do endereço, e só existem no escopo mailbox: digits_heavy marca o local-part dominado por dígitos (uma corrida de cinco ou mais, ou mais da metade dos caracteres), o padrão do endereço fabricado em massa, calibrado de propósito para não pegar o apelido com ano de nascimento; e name_email_score mede, de 0 a 1, quanto do local-part é coberto pelo nome lido no documento. Este último é informativo e não pontua: apelido legítimo é comum demais para virar agravante, e ele vem null quando não há caixa, não há OCR na verificação, ou o local-part não tem nenhum token com cara de nome.
// ip_risk: rede residencial, nada a apontar
{ "module": "ip_risk", "passed": true, "outcome": "approved", "score": 100,
"data": { "risk_score": 0, "level": "low", "provider_verdict": "clean", "network_measured": true,
"country": "BR", "asn": 28573, "asn_org": "OPERADORA X S.A.",
"connection": "residential", "tor": false, "datacenter": false, "anonymizer": false,
// proxy e vpn SEPARADOS: o anonymizer acima é só o "ou" dos dois.
"proxy": false, "vpn": false,
// comportamento RECENTE do endereço, como o fornecedor o declara
"recent_abuse": false, "bot": false, "abuse_velocity": "none",
"geo_mismatch": false, "timezone_mismatch": false, "asn_incoherent": false,
"ip_reuse_count": 1, "reasons": [] } }
// ip_risk: saída Tor, fora do país, fuso do navegador incoerente (review, NUNCA decline)
{ "module": "ip_risk", "passed": false, "outcome": "failed", "score": 40,
"data": { "risk_score": 60, "level": "high", "provider_verdict": "dirty", "network_measured": true,
"country": "NL", "asn": 60068, "asn_org": "DATACAMP LIMITED",
"connection": "anonymizer", "tor": true, "datacenter": false, "anonymizer": true,
"proxy": false, "vpn": true,
"recent_abuse": true, "bot": false, "abuse_velocity": "medium",
"geo_mismatch": true, "timezone_mismatch": true, "asn_incoherent": false,
"ip_reuse_count": 4,
"reasons": ["ip_tor", "ip_geo_mismatch", "ip_timezone_mismatch"] } }
// ip_risk: nenhuma camada de rede respondeu -> pending, e o módulo NÃO é cobrado
{ "module": "ip_risk", "passed": null, "outcome": "pending", "score": 0,
"data": { "provider_verdict": "not_cached", "network_measured": false,
"reason": "ip_intel_unavailable", "country": null, "asn": null,
"tor": null, "datacenter": null, "anonymizer": null,
// null nos SEIS: "o fornecedor não disse", jamais "disse que está limpo".
"proxy": null, "vpn": null,
"recent_abuse": null, "bot": null, "abuse_velocity": null } }
// email_risk: caixa analisada (o flow tem email_otp), endereço descartável
{ "module": "email_risk", "passed": false, "outcome": "failed", "score": 38,
"data": { "scope": "mailbox", "risk_score": 62, "level": "high",
"provider_verdict": "disposable", "email_domain": "tempmail.xyz",
"email_masked": "u***r@tempmail.xyz", "email_fp": "7c14ab…",
"disposable": true, "undeliverable": false, "role_based": false, "plus_alias": false,
"typosquat": false, "homoglyph": false, "masked_forwarder": false,
"suspicious_lexicon": true, "domain_age_days": 12,
// DE ONDE veio a afirmação: true = a NOSSA lista curada também listou o domínio
"disposable_listed": true, "forwarder_listed": false,
// padrão do endereço e coerência com o nome do documento (0..1, INFORMATIVA)
"digits_heavy": true, "name_email_score": 0.12,
"reasons": ["email_disposable", "email_suspicious_lexicon", "email_domain_recent"] } }
// email_risk: só o domínio existia (flow sem email_otp) -> o que NÃO foi olhado vem null
{ "module": "email_risk", "passed": null, "outcome": "pending", "score": 0,
"data": { "scope": "domain", "provider_verdict": "not_cached",
"email_domain": "empresa.com.br", "email_masked": null, "email_fp": null,
"role_based": null, "plus_alias": null, "disposable": null,
// as listas NOSSAS respondem sobre o DOMÍNIO, então continuam medindo aqui
"disposable_listed": false, "forwarder_listed": false,
// estes DOIS dependem da caixa: sem local-part não há o que medir
"digits_heavy": null, "name_email_score": null,
"reason": "email_not_provided" } }Em sandbox nada é consultado: o desfecho vem do sufixo do documento, como no resto do ambiente. Para o ip_risk: 33 datacenter, 44 saída Tor fora do país e 55 reputação indisponível (not_cached). Para o email_risk: 33 domínio descartável, 44 caixa de função com alias e 55 escopo de domínio.
A mesma dupla tem uma versão avançada, com um terceiro módulo de telefone ao lado: Verificação avançada de IP (ip_risk_plus), Risco avançado de e-mail (email_risk_plus) e Risco de telefone (telefone_risco). Os dois primeiros devolvem os MESMOS campos dos módulos de origem acima, com uma diferença de entrega: aqui o veredito nunca chega como não medido. Sem resposta da consulta o módulo defere, e o deferimento tem forma própria no payload: o item de check_details continua vindo com data, e é dentro dele que o deferimento se declara, com provider_verdict: "unavailable", reason: "provider_unavailable" e null em tudo que não foi medido. Nessa passagem o módulo não é cobrado: sai da conta só ele, e o resto do flow continua sendo cobrado normalmente. Nenhum campo é completado com "limpo".
O telefone_risco exige sms_otp no mesmo flow: o número analisado é o que o titular já provou controlar pelo código por SMS, nunca um número solto. Ele confirma a linha, não a pessoa, e não substitui a prova de posse por SMS nem a biometria. O número completo não trafega: só a máscara e o phone_fp, o mesmo pseudônimo que o sms_otp publica para o mesmo número. line_class é vocabulário fechado nosso (mobile, landline, voip, toll_free, premium, satellite, pager, unknown), nunca a string crua do fornecedor, e high_risk é derivado por nós: não há score cru de fornecedor no payload. Os três são portões suaves: um sinal alto leva a verificação para review com a evidência no webhook, nunca a denied automático.
// ip_risk_plus: mesma rede do ip_risk, agora com o veredito garantido (nunca not_cached)
{ "module": "ip_risk_plus", "passed": true, "outcome": "approved", "score": 100,
"data": { "risk_score": 0, "level": "low", "provider_verdict": "clean", "network_measured": true,
"country": "BR", "asn": 28573, "asn_org": "OPERADORA X S.A.",
"connection": "residential", "tor": false, "datacenter": false, "anonymizer": false,
"proxy": false, "vpn": false,
"recent_abuse": false, "bot": false, "abuse_velocity": "none",
"geo_mismatch": false, "timezone_mismatch": false, "asn_incoherent": false,
"ip_reuse_count": 1, "reasons": [], "reason": null } }
// ip_risk_plus: saída Tor, fora do país, abuso recente (review, NUNCA decline)
{ "module": "ip_risk_plus", "passed": false, "outcome": "failed", "score": 20,
"data": { "risk_score": 80, "level": "high", "provider_verdict": "dirty", "network_measured": true,
"country": "NL", "asn": 60068, "asn_org": "DATACAMP LIMITED",
"connection": "anonymizer", "tor": true, "datacenter": false, "anonymizer": true,
"proxy": false, "vpn": true,
"recent_abuse": true, "bot": false, "abuse_velocity": "high",
"geo_mismatch": true, "timezone_mismatch": true, "asn_incoherent": false,
"ip_reuse_count": 1,
// toda razão que pontuou aparece aqui, e "score" é sempre 100 menos "risk_score"
"reasons": ["ip_tor", "ip_geo_mismatch", "ip_timezone_mismatch",
"ip_recent_abuse", "ip_abuse_velocity_high"], "reason": null } }
// ip_risk_plus: sem veredito do fornecedor -> DEFERE. O "data" VEM, com null no que ninguém mediu,
// e só o MÓDULO sai da cobrança (o resto do flow segue cobrando)
{ "module": "ip_risk_plus", "passed": null, "outcome": "pending", "score": 0,
"data": { "risk_score": null, "level": null, "provider_verdict": "unavailable",
"network_measured": false,
"country": null, "asn": null, "asn_org": null, "connection": null,
"tor": null, "datacenter": null, "anonymizer": null, "proxy": null, "vpn": null,
"recent_abuse": null, "bot": null, "abuse_velocity": null,
"geo_mismatch": null, "timezone_mismatch": null, "asn_incoherent": null,
"ip_reuse_count": null, "reasons": [], "reason": "provider_unavailable" } }
// email_risk_plus: caixa analisada, entregabilidade real e idade do domínio garantidas
{ "module": "email_risk_plus", "passed": true, "outcome": "approved", "score": 100,
"data": { "scope": "mailbox", "risk_score": 0, "level": "low", "provider_verdict": "deliverable",
"email_domain": "gmail.com", "email_masked": "j***o@gmail.com", "email_fp": "b3f1c9…",
"disposable": false, "disposable_listed": false, "undeliverable": false,
"role_based": false, "plus_alias": false, "typosquat": false, "homoglyph": false,
"masked_forwarder": false, "forwarder_listed": false, "suspicious_lexicon": false,
"domain_age_days": 8200, "digits_heavy": false, "name_email_score": 0.82,
"reasons": [], "reason": null } }
// email_risk_plus: caixa NÃO entrega, domínio descartável e recente (review, NUNCA decline)
{ "module": "email_risk_plus", "passed": false, "outcome": "failed", "score": 8,
"data": { "scope": "mailbox", "risk_score": 92, "level": "high", "provider_verdict": "disposable",
"email_domain": "tempmail.xyz", "email_masked": "u***r@tempmail.xyz", "email_fp": "7c14ab…",
"disposable": true, "disposable_listed": true, "undeliverable": true,
"role_based": false, "plus_alias": false, "typosquat": false, "homoglyph": false,
"masked_forwarder": false, "forwarder_listed": false, "suspicious_lexicon": true,
"domain_age_days": 9, "digits_heavy": false, "name_email_score": 0.05,
"reasons": ["email_disposable", "email_undeliverable", "email_suspicious_lexicon",
"email_domain_recent"], "reason": null } }
// email_risk_plus: sem veredito do fornecedor -> DEFERE. O "data" VEM com null no que ninguém mediu:
// sobra o "scope" (o que teria sido analisado, caixa ou domínio) e nada do endereço, porque o
// deferimento não publica máscara, domínio nem pseudônimo. Só o MÓDULO sai da cobrança
{ "module": "email_risk_plus", "passed": null, "outcome": "pending", "score": 0,
"data": { "scope": "mailbox", "risk_score": null, "level": null,
"provider_verdict": "unavailable",
"email_domain": null, "email_masked": null, "email_fp": null,
"disposable": null, "disposable_listed": null, "undeliverable": null,
"role_based": null, "plus_alias": null, "typosquat": null, "homoglyph": null,
"masked_forwarder": null, "forwarder_listed": null, "suspicious_lexicon": null,
"domain_age_days": null, "digits_heavy": null, "name_email_score": null,
"reasons": [], "reason": "provider_unavailable" } }
// telefone_risco: linha móvel ativa, sem indício de abuso
{ "module": "telefone_risco", "passed": true, "outcome": "approved", "score": 100,
"data": { "risk_score": 0, "level": "low", "provider_verdict": "phone_clean",
"phone_masked": "+55 11 9****-**99", "phone_fp": "9f2c1a…", "country_code": "+55",
"valid": true, "active": true, "line_class": "mobile", "carrier": "OPERADORA X S.A.",
"voip": false, "prepaid": false, "risky": false, "recent_abuse": false,
"high_risk": false, "reasons": [], "reason": null } }
// telefone_risco: linha VOIP com abuso recente e reputação de risco (review, NUNCA decline)
{ "module": "telefone_risco", "passed": false, "outcome": "failed", "score": 35,
"data": { "risk_score": 65, "level": "high", "provider_verdict": "phone_risky",
"phone_masked": "+55 11 9****-**21", "phone_fp": "4ab8e2…", "country_code": "+55",
"valid": true, "active": true, "line_class": "voip", "carrier": "OPERADORA VIRTUAL LTDA",
"voip": true, "prepaid": false, "risky": true, "recent_abuse": true,
"high_risk": false,
"reasons": ["phone_risky", "phone_recent_abuse", "phone_voip"], "reason": null } }
// telefone_risco: sem veredito do fornecedor -> DEFERE. O "data" VEM: máscara, pseudônimo e código
// do país continuam (eles são nossos, não do fornecedor), o resto sai null, e só o MÓDULO sai da
// cobrança
{ "module": "telefone_risco", "passed": null, "outcome": "pending", "score": 0,
"data": { "risk_score": null, "level": null, "provider_verdict": "unavailable",
"phone_masked": "+55 11 9****-**99", "phone_fp": "9f2c1a…", "country_code": "+55",
"valid": null, "active": null, "line_class": null, "carrier": null,
"voip": null, "prepaid": null, "risky": null, "recent_abuse": null,
"high_risk": null, "reasons": [], "reason": "provider_unavailable" } }Em sandbox, o mesmo sufixo do documento decide o caminho, e não há veredito ausente: o ambiente de testes não encena queda do fornecedor, do mesmo jeito que não encena queda da nossa própria infraestrutura. Aqui o sufixo troca o dado devolvido, e não o desfecho: passed, outcome e score continuam saindo da tabela de sufixos do sandbox (00, 01 e 02), e qualquer outro sufixo aprova. Para o ip_risk_plus: 33 responde com rede de datacenter e 44 com saída Tor fora do país. Para o email_risk_plus: 33 domínio descartável, 44 caixa de função com alias e 55 escopo de domínio, com o veredito medido. Para o telefone_risco: 33 abuso recente, 44 linha VOIP e 55 número fora da faixa atribuída pela base. Ou seja: em sandbox dá para ver um payload de risco alto junto de outcome: "approved", o que não acontece em produção. Programe contra os campos, nunca contra o par que o sandbox mostra.
Pronto para integrar? A chave de sandbox sai no painel, logo depois do cadastro. Criar conta grátis