Validação de CPF em .NET/C#: consumindo a API SmartCPF com HttpClient

Tutorial prático de como validar e consultar CPF em aplicações .NET usando HttpClient e a API SmartCPF v2.

Redação Smart CPFRedação Smart CPF
·· 8 min de leitura
Validação de CPF em .NET/C#: consumindo a API SmartCPF com HttpClient

Integrar validação de CPF em aplicações .NET costuma envolver bibliotecas locais que apenas verificam o dígito verificador, sem confirmar se o documento realmente existe na base da Receita Federal ou se está regular. A API SmartCPF resolve isso expondo um endpoint REST que valida o formato, consulta a situação cadastral e retorna dados enriquecidos — nome, data de nascimento, e-mails, telefones e endereços — em uma única chamada. Este artigo mostra como consumir o endpoint GET /v2/individuals/{cpf} a partir de uma aplicação .NET usando HttpClient com autenticação via header X-API-KEY.

O endpoint de consulta individual

A SmartCPF disponibiliza a rota GET https://api.smartcpf.com.br/v2/individuals/{cpf}?package=X onde {cpf} pode ser enviado com ou sem formatação (pontos e traço) e o parâmetro package define o nível de detalhe do retorno. A autenticação é obrigatória e feita exclusivamente pelo header X-API-KEY — não há suporte a Authorization: Bearer, query string api_key ou qualquer outro esquema. O resposta segue um envelope padronizado com meta (metadados da consulta como consultId, balance, executionTimeMs) e result (dados do CPF consultado). Códigos de status HTTP: 200 para sucesso, 401 para chave inválida, 404 quando o CPF não é encontrado, 422 para CPF malformado e 429 quando o limite de requisições é excedido.

Vantagens de usar a API SmartCPF em .NET

1. Validação real, não apenas sintática
Bibliotecas locais conferem apenas o algoritmo do dígito verificador. A SmartCPF confirma se o CPF existe na base oficial e qual sua situação (Regular, Suspenso, Cancelado, Nulo).

2. Dados enriquecidos prontos para uso
O retorno já traz nome completo, data de nascimento, idade, nome da mãe, gênero, e-mails, telefones com operadora e tipo, e endereços — dispensando parsing ou cruzamento de bases.

3. Controle de custos via créditos
O campo balance no meta mostra o saldo de créditos em tempo real, permitindo implementar alertas ou bloqueios automáticos antes que a aplicação fique sem quota.

4. Rastreabilidade com consultId
Cada consulta recebe um UUID único (consultId), essencial para auditoria, suporte e idempotência em retentativas.

5. Latência baixa e previsível
O executionTimeMs costuma ficar abaixo de 100 ms, adequado para fluxos síncronos como cadastro de usuários ou checkout.

6. Sem dependências pesadas
HttpClient nativo do .NET basta; não há necessidade de SDKs específicos, facilitando manutenção e versionamento.

Desafios ao integrar validação de CPF via API

1. Gestão de chaves de API
A X-API-KEY deve ser armazenada com segurança (Key Vault, variáveis de ambiente, User Secrets) e rotacionada periodicamente — vazamento permite consumo indevido de créditos.

2. Tratamento de erros HTTP específicos
Códigos 401, 404, 422, 429 exigem caminhos distintos: reautenticação, validação de entrada, backoff exponencial ou fila de retentativa.

3. Dependência de rede externa
Falhas de conectividade, DNS ou timeout da API impactam a aplicação. Requer circuit breaker, timeout configurável e fallback (ex.: validação local apenas de dígito como degradação graciosa).

4. Conformidade LGPD
O retorno contém dados pessoais sensíveis. A aplicação deve garantir log mínimo (nunca logar result), criptografia em trânsito e retenção apenas pelo tempo necessário.

5. Versionamento da API
Mudanças no contrato (v2 → v3) podem quebrar integração. Monitorar changelog e testar em staging antes de promover é obrigatório.

Como implementar com a SmartCPF

O exemplo abaixo usa HttpClient configurado via IHttpClientFactory (padrão recomendado no .NET 6+), injeta a API key via IConfiguration, trata códigos de erro comuns e desserializa o envelope de resposta. O pacote System.Text.Json nativo cuida da serialização; nenhum pacote extra é necessário.

SmartCpfClient.cs
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace SmartCpfIntegration
{
    /// <summary>
    /// Cliente tipado para consumir a API SmartCPF v2.
    /// Registre no DI: services.AddHttpClient<SmartCpfClient>();
    /// </summary>
    public class SmartCpfClient
    {
        private readonly HttpClient _httpClient;
        private readonly string _apiKey;
        private readonly ILogger<SmartCpfClient> _logger;

        // Modelos mínimos para desserialização do envelope de resposta
        public class SmartCpfResponse
        {
            public Meta Meta { get; set; } = new();
            public Result Result { get; set; } = new();
            public bool Success { get; set; }
            public string[] Errors { get; set; } = Array.Empty<string>();
        }

        public class Meta
        {
            public string SearchType { get; set; } = "";
            public string ConsultId { get; set; } = "";
            public string User { get; set; } = "";
            public string Message { get; set; } = "";
            public string Ip { get; set; } = "";
            public bool Success { get; set; }
            public string ApiVersion { get; set; } = "";
            public DateTime Date { get; set; }
            public double ExecutionTimeMs { get; set; }
            public decimal Balance { get; set; }
        }

        public class Result
        {
            public string Cpf { get; set; } = "";
            public string Name { get; set; } = "";
            public string BirthDate { get; set; } = "";
            public int Age { get; set; }
            public string MotherName { get; set; } = "";
            public string Gender { get; set; } = "";
            public string Status { get; set; } = "";
            public string[] Emails { get; set; } = Array.Empty<string>();
            public Phone[] Phones { get; set; } = Array.Empty<Phone>();
            public Address[] Addresses { get; set; } = Array.Empty<Address>();
        }

        public class Phone
        {
            public string Number { get; set; } = "";
            public bool BlockedTelemarketing { get; set; }
            public string Operator { get; set; } = "";
            public string Type { get; set; } = "";
            public bool Whatsapp { get; set; }
        }

        public class Address
        {
            public string ZipCode { get; set; } = "";
            public string Street { get; set; } = "";
            public string Number { get; set; } = "";
            public string Complement { get; set; } = "";
            public string Neighborhood { get; set; } = "";
            public string City { get; set; } = "";
            public string State { get; set; } = "";
        }

        public SmartCpfClient(HttpClient httpClient, IConfiguration configuration, ILogger<SmartCpfClient> logger)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            // BaseAddress já configurada no Program.cs via AddHttpClient
            _apiKey = configuration["SmartCpf:ApiKey"]
                ?? throw new InvalidOperationException("SmartCpf:ApiKey não configurada.");

            // Header de autenticação obrigatório em TODA requisição
            _httpClient.DefaultRequestHeaders.Add("X-API-KEY", _apiKey);
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        /// <summary>
        /// Consulta um CPF na API SmartCPF v2.
        /// </summary>
        /// <param name="cpf">CPF com ou sem formatação (pontos/traço).</param>
        /// <param name="package">Pacote de dados (ex.: "X").</param>
        /// <returns>Resposta desserializada ou null em falhas não retentáveis.</returns>
        /// <exception cref="HttpRequestException">Erros de rede, 401, 429, 5xx.</exception>
        public async Task<SmartCpfResponse?> ConsultarCpfAsync(string cpf, string package = "X")
        {
            if (string.IsNullOrWhiteSpace(cpf))
                throw new ArgumentException("CPF não pode ser vazio.", nameof(cpf));

            // Remove formatação para garantir consistência
            var cpfLimpo = cpf.Replace(".", "").Replace("-", "").Trim();

            var url = $"v2/individuals/{cpfLimpo}?package={Uri.EscapeDataString(package)}";

            _logger.LogDebug("Consultando CPF {Cpf} na SmartCPF (package={Package})", cpfLimpo, package);

            HttpResponseMessage response;
            try
            {
                response = await _httpClient.GetAsync(url).ConfigureAwait(false);
            }
            catch (HttpRequestException ex)
            {
                _logger.LogError(ex, "Falha de rede ao consultar CPF {Cpf}", cpfLimpo);
                throw; // Deixa o chamador decidir retentativa (Polly, etc.)
            }

            // Tratamento por código de status
            switch (response.StatusCode)
            {
                case System.Net.HttpStatusCode.OK:
                    break; // Sucesso, continua para desserialização

                case System.Net.HttpStatusCode.Unauthorized:
                    _logger.LogError("API Key inválida ou expirada (401).");
                    throw new HttpRequestException("Autenticação falhou: X-API-KEY inválida.", null, response.StatusCode);

                case System.Net.HttpStatusCode.NotFound:
                    _logger.LogWarning("CPF {Cpf} não encontrado na base (404).", cpfLimpo);
                    return null; // Não encontrado não é erro de rede — chamador decide o que fazer

                case System.Net.HttpStatusCode.UnprocessableEntity:
                    _logger.LogWarning("CPF {Cpf} malformado (422).", cpfLimpo);
                    throw new HttpRequestException($"CPF inválido: {cpfLimpo}", null, response.StatusCode);

                case System.Net.HttpStatusCode.TooManyRequests:
                    var retryAfter = response.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(60);
                    _logger.LogWarning("Rate limit excedido (429). Retry-After: {RetryAfter}", retryAfter);
                    throw new HttpRequestException("Limite de requisições excedido.", null, response.StatusCode);

                default:
                    var errorBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    _logger.LogError("Erro inesperado {StatusCode}: {Body}", response.StatusCode, errorBody);
                    throw new HttpRequestException($"Erro da API: {(int)response.StatusCode} - {errorBody}", null, response.StatusCode);
            }

            // Desserialização com opções tolerantes a caso
            var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            };

            var result = JsonSerializer.Deserialize<SmartCpfResponse>(json, options);

            if (result is null || !result.Success)
            {
                _logger.LogWarning("Resposta da API indica falha: {Errors}", result?.Errors ?? Array.Empty<string>());
                return null;
            }

            _logger.LogInformation("Consulta realizada com sucesso. ConsultId: {ConsultId}, Balance: {Balance}, Tempo: {Ms}ms",
                result.Meta.ConsultId, result.Meta.Balance, result.Meta.ExecutionTimeMs);

            return result;
        }
    }

    // Exemplo de uso em um serviço de aplicação
    public class CpfValidationService
    {
        private readonly SmartCpfClient _client;
        private readonly ILogger<CpfValidationService> _logger;

        public CpfValidationService(SmartCpfClient client, ILogger<CpfValidationService> logger)
        {
            _client = client;
            _logger = logger;
        }

        public async Task<bool> ValidarCpfParaCadastroAsync(string cpf)
        {
            try
            {
                var response = await _client.ConsultarCpfAsync(cpf, "X");

                if (response is null)
                {
                    _logger.LogInformation("CPF {Cpf} não encontrado ou inválido.", cpf);
                    return false;
                }

                // Regras de negócio baseadas no retorno
                var status = response.Result.Status?.ToUpperInvariant();
                var isRegular = status == "REGULAR";

                _logger.LogInformation(
                    "CPF {Cpf} - Nome: {Nome}, Status: {Status}, Idade: {Idade}, E-mails: {EmailCount}, Telefones: {PhoneCount}, Saldo: {Balance}",
                    cpf,
                    response.Result.Name,
                    response.Result.Status,
                    response.Result.Age,
                    response.Result.Emails.Length,
                    response.Result.Phones.Length,
                    response.Meta.Balance);

                // Alerta de saldo baixo (ex.: menos de 5 créditos)
                if (response.Meta.Balance < 5)
                {
                    _logger.LogWarning("Saldo de créditos baixo: {Balance}. Considere recarregar.", response.Meta.Balance);
                }

                return isRegular;
            }
            catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
            {
                // Exemplo: enfileirar para retentativa posterior
                _logger.LogWarning("Rate limit atingido. CPF {Cpf} será reavaliado depois.", cpf);
                throw; // Ou retornar false e agendar retry
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Erro ao validar CPF {Cpf}", cpf);
                throw; // Deixa bubblar para middleware global de erro
            }
        }
    }
}

Resposta da API

response.json
{
  "meta": {
    "searchType": "CPF C",
    "consultId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user": "Fulano de Tal",
    "message": "CPF encontrado com sucesso",
    "ip": "127.0.0.1",
    "success": true,
    "apiVersion": "v2",
    "date": "2026-08-11T14:32:10.123Z",
    "executionTimeMs": 74.1,
    "balance": 9.77
  },
  "result": {
    "cpf": "111.111.111-11",
    "name": "João da Silva",
    "birthDate": "10/09/1992",
    "age": 33,
    "motherName": "Maria da Silva",
    "gender": "M",
    "status": "Regular",
    "emails": ["[email protected]"],
    "phones": [
      {
        "number": "(55) 99999-9999",
        "blockedTelemarketing": false,
        "operator": "VIVO",
        "type": "CELULAR",
        "whatsapp": false
      }
    ],
    "addresses": []
  },
  "success": true,
  "errors": []
}

O fluxo demonstrado resolve na prática:

  • Validação real de existência e regularidade — o campo result.status ("Regular") confirma se o CPF está ativo na Receita Federal.
  • Rastreabilidade total — meta.consultId (UUID) permite auditar cada consulta em logs, suporte ou conciliação de faturamento.
  • Controle de custos automático — meta.balance (9.77) expõe o saldo de créditos restante, viabilizando alertas proativos antes de interromper a operação.
  • Dados prontos para KYC/onboarding — result.name, birthDate, age, motherName, gender, emails, phones (com operadora, tipo e WhatsApp) e addresses eliminam necessidade de APIs adicionais.
  • Observabilidade de performance — meta.executionTimeMs (74.1 ms) permite SLA interno e alertas de degradação de latência.

Por que usar a SmartCPF em aplicações .NET

  • Integração nativa sem SDK — HttpClient + System.Text.Json dispensam dependências extras e mantêm o projeto leve.
  • Modelo de créditos previsível — pagamento por consulta com saldo em tempo real no header da resposta, sem surpresas na fatura.
  • Escalabilidade horizontal — a API aceita alto volume de requisições paralelas; basta configurar HttpClient com PooledConnectionLifetime e MaxConnectionsPerServer adequados.
  • Contrato estável e versionado — rota v2 garante que breaking changes só ocorram em nova versão, dando tempo de migração planejada.
  • Suporte a idempotência — o consultId permite deduplicar retentativas em caso de timeout de rede, evitando cobrança duplicada.

Conclusão

Validar CPF apenas pelo dígito verificador deixa lacunas de fraude e cadastro sujo. Consumir a API SmartCPF via HttpClient em .NET exige poucas linhas de código, traz dados completos para decisões de negócio (onboarding, KYC, antifraude) e expõe métricas operacionais (consultId, balance, executionTimeMs) essenciais para produção. O padrão IHttpClientFactory garante gerenciamento correto de conexões e DNS, enquanto o tratamento explícito de 401, 404, 422 e 429 torna a integração resiliente. Crie sua conta na SmartCPF e faça sua primeira consulta em minutos.

Redação Smart CPF

Sobre a redação

Redação Smart CPF

Autor do blog

Pronto para validar CPFs em segundos?

Consultas gratuitas para testar agora. Acesso imediato à documentação.