Como integrar validação de CPF em apps iOS com Swift e URLSession

Aprenda a integrar a validação de CPF via API em aplicativos iOS usando Swift e URLSession com exemplos completos e boas práticas.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como integrar validação de CPF em apps iOS com Swift e URLSession

Para integrar validação de CPF em apps iOS com Swift, crie um CpfService que usa URLSession com async/await, defina as structs CpfResponse e CpfData conformando ao protocolo Codable e faça um GET para https://api.cpfhub.io/cpf/{CPF} com o header x-api-key. O plano gratuito da CPFHub.io oferece 50 consultas por mês sem cartão de crédito, suficiente para testes e apps em fase inicial.

Introdução

Aplicativos iOS que operam no mercado brasileiro frequentemente precisam validar o CPF de seus usuários durante processos de cadastro, onboarding ou transações financeiras. Fintechs, marketplaces, aplicativos de mobilidade e plataformas de saúde são exemplos de segmentos que dependem dessa validação para garantir a identidade do usuário e prevenir fraudes.

O Swift, linguagem nativa da Apple para desenvolvimento iOS, oferece o URLSession como a forma padrão de realizar requisições HTTP.


Pré-requisitos

  • Xcode 15+ -- Ambiente de desenvolvimento da Apple.
  • Swift 5.9+ -- Versão recomendada para projetos modernos.
  • Conta na CPFHub.io -- Para obter a chave de API. O plano gratuito oferece 50 consultas/mês.
  • App Transport Security -- HTTPS é obrigatório no iOS, e a API da CPFHub.io já opera com HTTPS.

Modelando a resposta da API

Crie as structs que representam o JSON retornado pela API, conformando ao protocolo Codable:

struct CpfResponse: Codable {
    let success: Bool
    let data: CpfData?
}

struct CpfData: Codable {
    let cpf: String
    let name: String
    let nameUpper: String
    let gender: String
    let birthDate: String
    let day: Int
    let month: Int
    let year: Int
}

A resposta esperada da API:

{
    "success": true,
    "data": {
    "cpf": "12345678900",
    "name": "João da Silva",
    "nameUpper": "JOÃO DA SILVA",
    "gender": "M",
    "birthDate": "15/06/1990",
    "day": 15,
    "month": 6,
    "year": 1990
    }
}

Criando o serviço de consulta com URLSession

Abaixo está a implementação de um serviço que encapsula a chamada à API usando URLSession com async/await:

import Foundation

enum CpfServiceError: Error, LocalizedError {
    case cpfInvalido
    case chaveNaoConfigurada
    case erroHTTP(statusCode: Int)
    case timeout
    case respostInvalida
    case cpfNaoEncontrado

    var errorDescription: String? {
    switch self {
    case .cpfInvalido:
    return "CPF inválido. Informe 11 dígitos numéricos."
    case .chaveNaoConfigurada:
    return "Chave de API não configurada."
    case .erroHTTP(let code):
    return "Erro HTTP: \(code)"
    case .timeout:
    return "A requisição excedeu o tempo limite."
    case .respostInvalida:
    return "Resposta inválida da API."
    case .cpfNaoEncontrado:
    return "CPF não encontrado na base de dados."
    }
    }
}

class CpfService {

    private let apiKey: String
    private let baseURL = "https://api.cpfhub.io/cpf/"
    private let session: URLSession

    init(apiKey: String) {
    self.apiKey = apiKey

    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 10
    config.timeoutIntervalForResource = 15
    self.session = URLSession(configuration: config)
    }

    func consultarCpf(_ cpf: String) async throws -> CpfData {
    let cpfLimpo = cpf.replacingOccurrences(
    of: "[^0-9]", with: "", options: .regularExpression
    )

    guard cpfLimpo.count == 11 else {
    throw CpfServiceError.cpfInvalido
    }

    guard !apiKey.isEmpty else {
    throw CpfServiceError.chaveNaoConfigurada
    }

    guard let url = URL(string: "\(baseURL)\(cpfLimpo)") else {
    throw CpfServiceError.cpfInvalido
    }

    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue(apiKey, forHTTPHeaderField: "x-api-key")
    request.setValue("application/json", forHTTPHeaderField: "Accept")

    do {
    let (data, response) = try await session.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse else {
    throw CpfServiceError.respostInvalida
    }

    switch httpResponse.statusCode {
    case 200:
    let cpfResponse = try JSONDecoder().decode(
    CpfResponse.self, from: data
    )
    guard cpfResponse.success, let cpfData = cpfResponse.data else {
    throw CpfServiceError.cpfNaoEncontrado
    }
    return cpfData
    default:
    throw CpfServiceError.erroHTTP(
    statusCode: httpResponse.statusCode
    )
    }
    } catch let error as URLError where error.code == .timedOut {
    throw CpfServiceError.timeout
    }
    }
}

Integrando com SwiftUI

Para aplicativos que utilizam SwiftUI, crie um ViewModel com @Published para gerenciar o estado:

import SwiftUI

@MainActor
class CpfViewModel: ObservableObject {

    @Published var cpfInput: String = ""
    @Published var resultado: CpfData?
    @Published var erro: String?
    @Published var carregando: Bool = false

    private let service: CpfService

    init() {
    self.service = CpfService(apiKey: "SUA_CHAVE_DE_API")
    }

    func consultar() {
    erro = nil
    resultado = nil
    carregando = true

    Task {
    do {
    let dados = try await service.consultarCpf(cpfInput)
    self.resultado = dados
    } catch {
    self.erro = error.localizedDescription
    }
    self.carregando = false
    }
    }
}

Tela de consulta em SwiftUI

struct ConsultaCpfView: View {

    @StateObject private var viewModel = CpfViewModel()

    var body: some View {
    NavigationView {
    VStack(spacing: 20) {
    TextField("CPF (somente números)", text: $viewModel.cpfInput)
    .keyboardType(.numberPad)
    .textFieldStyle(.roundedBorder)
    .padding(.horizontal)

    Button(action: { viewModel.consultar() }) {
    Text(viewModel.carregando ? "Consultando..." : "Consultar")
    .frame(maxWidth: .infinity)
    }
    .buttonStyle(.borderedProminent)
    .disabled(viewModel.carregando)
    .padding(.horizontal)

    if let dados = viewModel.resultado {
    VStack(alignment: .leading, spacing: 8) {
    Text("Nome: \(dados.name)")
    Text("CPF: \(dados.cpf)")
    Text("Nascimento: \(dados.birthDate)")
    Text("Gênero: \(dados.gender)")
    }
    .padding()
    }

    if let erro = viewModel.erro {
    Text(erro)
    .foregroundColor(.red)
    .padding()
    }

    Spacer()
    }
    .navigationTitle("Validação de CPF")
    }
    }
}

Testando com cURL

Para validar rapidamente o comportamento da API antes de integrar no app:

curl -X GET https://api.cpfhub.io/cpf/12345678900 \
    -H "x-api-key: SUA_CHAVE_DE_API" \
    -H "Accept: application/json" \
    --max-time 10

Boas práticas para iOS

  • Chave de API -- Em produção, nunca armazene a chave diretamente no código. Utilize um back-end intermediário que faz o proxy da requisição, protegendo a chave no servidor.

  • Timeout -- Configure timeoutIntervalForRequest no URLSessionConfiguration para evitar travamentos.

  • Thread principal -- Nunca faça chamadas de rede na main thread. Utilize async/await ou completionHandlers para manter a interface responsiva.

  • Validação local -- Valide os dígitos verificadores do CPF localmente antes de consultar a API, economizando consultas.

  • Monitoramento de consumo -- Controle o número de consultas realizadas no mês para evitar cobranças de excedente inesperadas (R$ 0,15/consulta adicional).


Perguntas frequentes

Como proteger a chave de API em um app iOS?

A chave de API nunca deve ficar embutida no código do app, pois pode ser extraída por engenharia reversa. A abordagem correta é criar um back-end intermediário (proxy) que faz a chamada à CPFHub.io no servidor e expõe apenas um endpoint autenticado para o app. Assim, a x-api-key fica protegida no ambiente de servidor, fora do alcance de usuários maliciosos.

A API CPFHub.io retorna 429 quando o limite de consultas é atingido?

Não. A CPFHub.io não bloqueia requisições nem retorna 429. Quando o limite do plano é ultrapassado, as consultas continuam funcionando normalmente e o excedente é cobrado a R$ 0,15 por consulta. Para controlar o consumo no app, mantenha um contador local ou use o painel em app.cpfhub.io.

Como lidar com timeout na chamada à API via URLSession?

Configure timeoutIntervalForRequest (tempo para receber o primeiro byte) e timeoutIntervalForResource (tempo total da operação) no URLSessionConfiguration. Para a CPFHub.io, com latência média de ~900ms, valores de 10s e 15s respectivamente são adequados. Trate o erro URLError.timedOut e exiba uma mensagem clara ao usuário.

Como garantir conformidade com a LGPD em apps iOS que validam CPF?

Informe ao usuário no momento do cadastro que o CPF será consultado para verificação de identidade, documente a base legal para o tratamento e não armazene o número do CPF no dispositivo além do necessário para a operação, conforme orienta a ANPD. Utilize o Secure Enclave ou Keychain para armazenar a chave de API com segurança no dispositivo.


Conclusão

Integrar a validação de CPF em aplicativos iOS usando Swift e URLSession é um processo direto que se beneficia dos recursos modernos da linguagem, como async/await e Codable. Com a API da CPFHub.io, o app recebe nome, data de nascimento e gênero do titular em uma única chamada, tornando o onboarding mais rápido e seguro.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e adicione validação de CPF ao seu app iOS com Swift em menos de uma hora.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp