CPFHub.io
Start for free

Python SDK

Official SDK for Python 3.8+. It makes the Simple Lookup (GET /cpf/{cpf}) and returns the API's JSON as a dict. A CPF is Brazil's individual taxpayer ID.

Installation

bash
pip install cpfhub

With Poetry:

bash
poetry add cpfhub

Requirements: Python 3.8+

Initialization

Python
import os
from cpfhub import CPFHub

client = CPFHub(api_key=os.environ["CPFHUB_API_KEY"])

The client sends the key in the x-api-key header and uses a 10-second timeout. It can also be used as a context manager, which closes the connection when the block ends:

Python
with CPFHub(api_key=os.environ["CPFHUB_API_KEY"]) as client:
    result = client.lookup("12345678909")

Constructor parameters

ParameterTypeDescription
api_keystrYour API key (required). If empty, raises ValueError

Methods

client.lookup(cpf)

Looks up a CPF and returns the API response body as a dict.

Python
result = client.lookup("123.456.789-09")
print(result["data"]["name"])       # "Fulano de Tal"
print(result["data"]["birthDate"])  # "15/06/1990"

Parameters:

ParameterTypeDescription
cpfstrCPF with or without formatting

Returns: a dict in the Simple Lookup format:

Python
{
    "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,
    },
}

The Real-Time Lookup and the batch lookup are made through the REST API: POST https://api.cpfhub.io/cpf/realtime and POST https://api.cpfhub.io/cpf/bulk.

⚠

Do not use client.get_quota()

Version 1.0.0 of the package includes a get_quota() method that calls the wrong address and does not work. To see your balance and plan, call GET https://api.cpfhub.io/quota directly (it does not use a credit).

Error handling

  • CPF without 11 digits: lookup raises ValueError before calling the API (no credit is used).
  • 4xx and 5xx responses: the SDK raises httpx.HTTPStatusError. The status is in e.response.status_code and the API body in e.response.json(). The error field comes as text ("...") or as an object ({"message": "..."}), depending on the status.
Python
import os
import httpx
from cpfhub import CPFHub

client = CPFHub(api_key=os.environ["CPFHUB_API_KEY"])

try:
    result = client.lookup("12345678909")
except httpx.HTTPStatusError as e:
    print(e.response.status_code)  # 404
    print(e.response.json())       # {"success": False, "data": None, "error": {"message": "CPF não encontrado na base de dados"}}  (the API replies in Portuguese: "CPF not found in the database")
StatusReason
401Missing or invalid API key
403Credits exhausted or blocked account
404CPF not found (no credit is used)
422Incorrect check digit (no credit is used)
429Requests-per-minute limit: wait the number of seconds in the Retry-After header

Full list in Error Codes.

Integration examples

FastAPI

Python
import os
import httpx
from fastapi import FastAPI, HTTPException
from cpfhub import CPFHub

app = FastAPI()
client = CPFHub(api_key=os.environ["CPFHUB_API_KEY"])

@app.get("/cpf/{cpf}")
def lookup_cpf_route(cpf: str):
    try:
        return client.lookup(cpf)["data"]
    except ValueError:
        raise HTTPException(status_code=400, detail="CPF must contain 11 digits")
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            raise HTTPException(status_code=404, detail="CPF not found")
        if e.response.status_code == 422:
            raise HTTPException(status_code=422, detail="Invalid CPF")
        # 401, 403, 429 and 5xx: key, credits or rate limit. Log it and do not expose it to the client.
        try:
            error_detail = e.response.json()
        except ValueError:
            error_detail = e.response.text
        print("CPFHub.io", e.response.status_code, error_detail)
        raise HTTPException(status_code=503, detail="CPF lookup unavailable right now")

Django view

Python
import os
import httpx
from django.http import JsonResponse
from cpfhub import CPFHub

client = CPFHub(api_key=os.environ["CPFHUB_API_KEY"])

def lookup_cpf_route(request, cpf):
    try:
        data = client.lookup(cpf)["data"]
        return JsonResponse({"name": data["name"], "gender": data["gender"]})
    except ValueError:
        return JsonResponse({"error": "CPF must contain 11 digits"}, status=400)
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            return JsonResponse({"error": "CPF not found"}, status=404)
        if e.response.status_code == 422:
            return JsonResponse({"error": "Invalid CPF"}, status=422)
        # 401, 403, 429 and 5xx: key, credits or rate limit. Do not expose it to the client.
        return JsonResponse({"error": "CPF lookup unavailable right now"}, status=503)

Form validation

Python
import os
import httpx
from cpfhub import CPFHub

client = CPFHub(api_key=os.environ["CPFHUB_API_KEY"])

def validate_cpf_onboarding(cpf: str) -> dict:
    try:
        data = client.lookup(cpf)["data"]
        return {"valid": True, "name": data["name"]}
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            return {"valid": False, "name": None}
        raise

Repository and support


Updated on October 3, 2026