Criar conta grátis

Documentação
Ver em Markdown

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.

!Limites honestos. VPN corporativa, rede de hotel, CGNAT de operadora móvel, domínio próprio recém registrado e caixa de função de um MEI são o cotidiano de gente legítima: trate estes dois como agravantes em conjunto, nunca como veredito. 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