CPFHub.io
Start for free

Look up a CPF with Ruby on Rails

Look up a CPF (Brazil's individual taxpayer ID) with Ruby on Rails using a service object with Net::HTTP, called from a controller. The API key lives in the Rails credentials.

Using Cursor, Lovable, v0 or another AI? Copy the Simple Lookup prompt and paste it into your assistant.

Open in Cursor

Before you start

  1. Create a free account at app.cpfhub.io: the Free plan includes 50 credits and does not ask for a card.
  2. Copy your API key from app.cpfhub.io/api-keys.
  3. Store the key in an environment variable, never in your code:
bash
export CPFHUB_API_KEY="sua_api_key"

Example

Store the key in the credentials (bin/rails credentials:edit) as cpfhub_api_key, or in the CPFHUB_API_KEY environment variable.

Ruby
# app/services/cpfhub_client.rb
require 'net/http'

class CpfhubClient
  class Error < StandardError; end

  # Returns the "data" hash, or nil when the CPF is not in the database (404).
  def self.lookup(cpf)
    uri = URI("https://api.cpfhub.io/cpf/#{cpf}")
    req = Net::HTTP::Get.new(uri)
    req['x-api-key'] = Rails.application.credentials.cpfhub_api_key || ENV.fetch('CPFHUB_API_KEY')

    res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, open_timeout: 5, read_timeout: 10) do |http|
      http.request(req)
    end
    body = JSON.parse(res.body)

    case res.code.to_i
    when 200 then body['data']
    when 404 then nil
    else
      # error is a string ("...") or an object ({ "message" => "..." })
      error = body['error']
      raise Error, "#{res.code}: #{error.is_a?(Hash) ? error['message'] : error}"
    end
  end
end
Ruby
# app/controllers/cpfs_controller.rb
class CpfsController < ApplicationController
  def show
    cpf = params[:id].to_s.gsub(/\D/, '')
    return render(json: { error: 'CPF must have 11 digits' }, status: :bad_request) unless cpf.length == 11

    data = CpfhubClient.lookup(cpf)
    if data
      render json: data
    else
      render json: { error: 'CPF not found' }, status: :not_found
    end
  rescue CpfhubClient::Error => e
    # 401, 403, 422, 429 and 5xx: log it and do not expose details to the client
    Rails.logger.error("CPFHub.io #{e.message}")
    render json: { error: 'CPF lookup is unavailable right now' }, status: :service_unavailable
  end
end

Add the route resources :cpfs, only: :show to config/routes.rb and test it with curl http://localhost:3000/cpfs/12345678909.

Response

Found CPF (200, uses 1 credit):

JSON
{
  "success": true,
  "data": {
    "cpf": "12345678909",
    "name": "Fulano de Tal",
    "nameUpper": "FULANO DE TAL",
    "gender": "M",
    "birthDate": "15/06/1990",
    "day": 15,
    "month": 6,
    "year": 1990
  }
}

CPF not found (404, does not use a credit):

JSON
{
  "success": false,
  "data": null,
  "error": { "message": "CPF não encontrado na base de dados" }
}

The CPF 12345678909 is fictional, used only in the examples. gender can be null. The error.message text comes from the API in Portuguese ("CPF not found in the database").

Errors

StatusWhat it meansWhat to do
404CPF is not in the databaseTreat it as "not found". Does not use a credit.
400 / 422CPF does not have 11 digits or has an invalid check digitFix the input. Does not use a credit.
401Missing or invalid API keyCheck the CPFHUB_API_KEY variable.
403Credits used up or inactive accountCheck your balance with GET /quota or top up in the dashboard.
429Per-minute request limitWait the number of seconds in the Retry-After header and try again.
5xxTemporary failureTry again after a few seconds.

The error field can be text ("error": "...") or an object ("error": { "message": "..." }), depending on the status. The examples above handle both formats. Full list in Error Codes.

Next steps