# Como Validar CPF em Tempo Real Usando Java e APIs REST

> Aprenda a validar CPF em tempo real usando Java com APIs REST, combinando validação algorítmica e consulta via API para máxima segurança.

**Publicado:** 16/09/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/validar-cpf-tempo-real-java-apis-rest

---


Para validar CPF em tempo real com Java, combine a validação algorítmica local (verificação dos dígitos verificadores, instantânea) com uma chamada GET à API REST da CPFHub.io usando o `HttpClient` nativo ou um serviço Spring. A validação algorítmica filtra CPFs com formato inválido antes que qualquer chamada de rede seja feita; a consulta via API confirma a existência real do documento e retorna nome, data de nascimento e gênero em ~900ms.

## Introdução

A validação de CPF em tempo real é um requisito comum em aplicações de cadastro, checkout e onboarding. A abordagem mais robusta combina validação algorítmica local, que é instantânea, com consulta via API REST para verificar a existência real do CPF. Em Java, essa combinação pode ser implementada de forma eficiente e thread-safe, atendendo a cenários de alta concorrência.

---

## Validação algorítmica local

A validação algorítmica verifica os dígitos verificadores do CPF sem necessidade de chamada externa.

```java
public class CpfValidator {

 private CpfValidator() {}

 public static boolean validarAlgoritmo(String cpf) {
 String cpfLimpo = cpf.replaceAll("\\D", "");

 if (cpfLimpo.length() != 11) {
 return false;
 }

 // Verificar se todos os dígitos são iguais
 if (cpfLimpo.chars().distinct().count() == 1) {
 return false;
 }

 // Validar primeiro dígito verificador
 int soma = 0;
 for (int i = 0; i < 9; i++) {
 soma += Character.getNumericValue(cpfLimpo.charAt(i))
 * (10 - i);
 }
 int resto = (soma * 10) % 11;
 if (resto == 10) resto = 0;
 if (resto != Character.getNumericValue(cpfLimpo.charAt(9))) {
 return false;
 }

 // Validar segundo dígito verificador
 soma = 0;
 for (int i = 0; i < 10; i++) {
 soma += Character.getNumericValue(cpfLimpo.charAt(i))
 * (11 - i);
 }
 resto = (soma * 10) % 11;
 if (resto == 10) resto = 0;

 return resto == Character.getNumericValue(cpfLimpo.charAt(10));
 }

 public static String formatar(String cpf) {
 String limpo = cpf.replaceAll("\\D", "");
 return String.format("%s.%s.%s-%s",
 limpo.substring(0, 3),
 limpo.substring(3, 6),
 limpo.substring(6, 9),
 limpo.substring(9, 11));
 }
}
```

| Validação | Tempo | Cobertura |
|---|---|---|
| Formato (11 dígitos) | < 0.001ms | Erros de digitação |
| Dígitos iguais | < 0.001ms | CPFs triviais (111.111.111-11) |
| Dígitos verificadores | < 0.01ms | CPFs com números inventados |
| Consulta via API | 100-500ms | Existência real do CPF |

---

## Serviço de validação em tempo real

O serviço combina validação local e consulta via API com cache para otimizar performance.

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CpfValidationService {

 private final HttpClient httpClient;
 private final String apiKey;
 private final ObjectMapper mapper;
 private final Map<String, ValidationResult> cache;

 public CpfValidationService(String apiKey) {
 this.httpClient = HttpClient.newBuilder()
 .connectTimeout(Duration.ofSeconds(5))
 .build();
 this.apiKey = apiKey;
 this.mapper = new ObjectMapper();
 this.cache = new ConcurrentHashMap<>();
 }

 public ValidationResult validarTempoReal(String cpf) {
 String cpfLimpo = cpf.replaceAll("\\D", "");

 // Etapa 1: Validação algorítmica
 if (!CpfValidator.validarAlgoritmo(cpfLimpo)) {
 return new ValidationResult(
 false, "algoritmo", "CPF invalido", null
 );
 }

 // Etapa 2: Verificar cache
 ValidationResult cached = cache.get(cpfLimpo);
 if (cached != null) {
 return new ValidationResult(
 cached.valido(), "cache",
 cached.mensagem(), cached.dados()
 );
 }

 // Etapa 3: Consulta via API
 try {
 HttpRequest request = HttpRequest.newBuilder()
 .uri(URI.create(
 "https://api.cpfhub.io/cpf/" + cpfLimpo
 ))
 .header("x-api-key", apiKey)
 .timeout(Duration.ofSeconds(5))
 .GET()
 .build();

 HttpResponse<String> response = httpClient.send(
 request,
 HttpResponse.BodyHandlers.ofString()
 );

 JsonNode root = mapper.readTree(response.body());

 if (root.get("success").asBoolean()) {
 JsonNode data = root.get("data");
 Map<String, String> dados = Map.of(
 "nome", data.get("name").asText(),
 "genero", data.get("gender").asText(),
 "nascimento", data.get("birthDate").asText()
 );

 ValidationResult result = new ValidationResult(
 true, "api", "CPF valido", dados
 );
 cache.put(cpfLimpo, result);
 return result;
 }

 return new ValidationResult(
 false, "api", "CPF nao encontrado", null
 );

 } catch (Exception e) {
 // Fallback: se a API falhar, aceitar com base
 // na validação algorítmica
 return new ValidationResult(
 true, "fallback",
 "Validado localmente (API indisponivel)",
 null
 );
 }
 }
}

public record ValidationResult(
 boolean valido,
 String fonte,
 String mensagem,
 Map<String, String> dados
) {}
```

---

## Endpoint REST para validação em tempo real

Exponha o serviço como endpoint REST para consumo por frontends ou outros serviços.

```java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/validar")
public class CpfValidationController {

 private final CpfValidationService validationService;

 public CpfValidationController(
 CpfValidationService validationService) {
 this.validationService = validationService;
 }

 @GetMapping("/cpf/{cpf}")
 public ResponseEntity<ValidationResult> validar(
 @PathVariable String cpf) {
 ValidationResult resultado =
 validationService.validarTempoReal(cpf);
 return ResponseEntity.ok(resultado);
 }

 @PostMapping("/cpf/lote")
 public ResponseEntity<Map<String, Object>> validarLote(
 @RequestBody List<String> cpfs) {

 List<ValidationResult> resultados = cpfs.stream()
 .map(validationService::validarTempoReal)
 .toList();

 long validos = resultados.stream()
 .filter(ValidationResult::valido)
 .count();

 return ResponseEntity.ok(Map.of(
 "total", cpfs.size(),
 "validos", validos,
 "invalidos", cpfs.size() - validos,
 "resultados", resultados
 ));
 }
}
```

| Endpoint | Método | Descrição |
|---|---|---|
| `/api/validar/cpf/{cpf}` | GET | Validação individual em tempo real |
| `/api/validar/cpf/lote` | POST | Validação de múltiplos CPFs |

---

## Bean Validation customizado

Crie uma anotação customizada para validar CPF em DTOs automaticamente.

```java
// CpfValido.java
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CpfValidoValidator.class)
public @interface CpfValido {
 String message() default "CPF invalido";
 Class<?>[] groups() default {};
 Class<? extends Payload>[] payload() default {};
}

// CpfValidoValidator.java
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

public class CpfValidoValidator
 implements ConstraintValidator<CpfValido, String> {

 @Override
 public boolean isValid(String cpf,
 ConstraintValidatorContext context) {
 if (cpf == null || cpf.isBlank()) {
 return false;
 }
 return CpfValidator.validarAlgoritmo(cpf);
 }
}

// Uso em DTO
public class CadastroRequest {

 @CpfValido(message = "CPF informado e invalido")
 private String cpf;

 private String nome;

 // Getters e setters
 public String getCpf() { return cpf; }
 public void setCpf(String cpf) { this.cpf = cpf; }
 public String getNome() { return nome; }
 public void setNome(String nome) { this.nome = nome; }
}
```

---

## Métricas de performance

Monitore a performance da validação em tempo real com Micrometer.

```java
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;

@Service
public class CpfValidationServiceMetricas {

 private final Timer validacaoTimer;
 private final CpfValidationService validationService;

 public CpfValidationServiceMetricas(
 MeterRegistry registry,
 CpfValidationService validationService) {
 this.validationService = validationService;
 this.validacaoTimer = Timer.builder("cpf.validacao")
 .description("Tempo de validacao de CPF")
 .register(registry);
 }

 public ValidationResult validar(String cpf) {
 return validacaoTimer.record(
 () -> validationService.validarTempoReal(cpf)
 );
 }
}
```

---

## Perguntas frequentes

### Por que combinar validação algorítmica e consulta via API em Java?
A validação algorítmica é instantânea (sub-millisegundo) e elimina CPFs com formato inválido ou dígitos verificadores errados antes de qualquer chamada de rede. A consulta via API confirma a existência real do CPF e retorna dados como nome e data de nascimento. Juntas, as duas camadas reduzem tanto o volume de chamadas externas quanto a taxa de falsos positivos no cadastro.

### Como implementar cache thread-safe para a validação de CPF em Java?
Use `ConcurrentHashMap` para armazenar resultados recentes. A chave é o CPF sanitizado (apenas dígitos) e o valor é o `ValidationResult`. Em ambientes com alta concorrência, considere adicionar TTL com `Caffeine` ou `Guava Cache` para evitar servir dados desatualizados. O cache é especialmente útil em validações em lote onde o mesmo CPF pode aparecer múltiplas vezes.

### Como configurar timeout adequado para a API de CPF em Java?
Configure timeout de conexão em 5 segundos e timeout de leitura em 10 segundos. A API da CPFHub.io tem latência de ~900ms em condições normais, portanto timeouts muito curtos podem gerar falsos negativos. Com `HttpClient` nativo, use `.timeout(Duration.ofSeconds(10))` no `HttpRequest`; com Spring RestTemplate, configure via `RestTemplateBuilder.setReadTimeout()`.

### O que fazer quando a API de CPF retorna erro ou fica indisponível?
Implemente um fallback que retorna o resultado da validação algorítmica com `fonte = "fallback"`, indicando que o CPF passou apenas pela verificação local. Registre o evento para monitoramento. A API da CPFHub.io não bloqueia consultas ao atingir o limite do plano — ela cobra R$0,15 por consulta excedente e continua respondendo normalmente, então erros de disponibilidade são raros e geralmente transitórios.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## Conclusão

A validação de CPF em tempo real em Java combina a velocidade da validação algorítmica local com a precisão da consulta via API REST. O uso de cache thread-safe com ConcurrentHashMap, fallback para cenários de indisponibilidade e Bean Validation customizada para DTOs cria um sistema robusto e reutilizável. As métricas com Micrometer permitem monitorar a performance e identificar gargalos em produção.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a validação de CPF em tempo real na sua aplicação Java em menos de 30 minutos.

