CPFHub.io
Start for free

Platforms

Integrations with the main automation and AI frameworks. Use the CPFHub.io API directly or through the MCP Server. A CPF is Brazil's individual taxpayer ID.

n8n

Use the HTTP Request node to call the API directly in workflows.

Node configuration:

FieldValue
MethodGET
URLhttps://api.cpfhub.io/cpf/{{ $json.cpf }}
AuthenticationGeneric Credential Type → Header Auth
Header Auth: Namex-api-key
Header Auth: Valueyour API key (stored in the credential, not in the workflow)
Options → Responseturn on Include Response Headers and Status and Never Error

By default, n8n stops the workflow on any 4xx response, including the 404 for a CPF not found. With Never Error and Include Response Headers and Status turned on, the node always continues and returns statusCode, headers and body.

Example workflow: CPF validation at signup

  1. Trigger: Webhook receives { cpf, email, nome }
  2. HTTP Request: looks up GET /cpf/{{ $json.cpf }}
  3. Switch on {{ $json.statusCode }}:
    • 200: sends {{ $json.body.data.name }} to the CRM or creates the record in the database
    • 404: CPF not found (no charge). Ask the user to check what they typed
    • 429: wait the number of seconds in {{ $json.headers["retry-after"] }} (Wait node) and try again
    • others: alert the team. See the codes in Error Codes

Make (Integromat)

In Make, use the HTTP: Make a Request module.

Configuration:

URL: https://api.cpfhub.io/cpf/{{cpf}}
Method: GET
Headers:
  x-api-key: {{api_key}}
Parse response: Yes
Evaluate all states as errors (except for 2xx and 3xx): No

Turn off Evaluate all states as errors. With the option on (the default), the 404 for a CPF not found becomes an error and stops the scenario.

Typical scenario:

  1. Watch Records (Airtable / Google Sheets): detects a new record with a CPF
  2. HTTP: Make a Request: looks up the CPF on CPFHub.io
  3. Router with filters on Status code: 200 continues to the next step, 404 marks the record as "CPF not found", and the rest go to an alert route
  4. Update Record: fills in name and date of birth on the original record

Zapier

Use the Zap with the Webhooks by Zapier app to call the API:

  1. Trigger: any event (form, CRM, spreadsheet)
  2. Action: Webhooks by Zapier → GET
    • URL: https://api.cpfhub.io/cpf/{{cpf}}
    • Headers: x-api-key: YOUR_API_KEY
  3. Next action: use the data.name and data.birthDate fields from the response

LangChain

Python

Requires langchain>=1.0 and langchain-openai.

Python
import os
import re
import requests
from langchain.agents import create_agent
from langchain.tools import tool

API_KEY = os.environ["CPFHUB_API_KEY"]

@tool
def lookup_cpf(cpf: str) -> str:
    """Looks up data for a person from their Brazilian CPF.
    Returns full name, gender and date of birth."""
    digits = re.sub(r"\D", "", cpf)
    r = requests.get(
        f"https://api.cpfhub.io/cpf/{digits}",
        headers={"x-api-key": API_KEY},
        timeout=10,
    )
    if r.status_code == 404:
        return "CPF not found. Ask the user to check what they typed."
    if not r.ok:
        return f"Error {r.status_code} while looking up the CPF."
    data = r.json()["data"]
    return f"Name: {data['name']}, Date of birth: {data['birthDate']}, Gender: {data['gender']}"

agent = create_agent(
    model="openai:gpt-4o",
    tools=[lookup_cpf],
    system_prompt="Use lookup_cpf to validate identities. Never repeat the full CPF.",
)

result = agent.invoke({"messages": [{"role": "user", "content": "Validate CPF 123.456.789-09"}]})
print(result["messages"][-1].content)

TypeScript / LangChain.js

TypeScript
import { ChatOpenAI } from '@langchain/openai'
import { tool } from '@langchain/core/tools'
import { z } from 'zod'
async function lookupCpf(cpf: string) {
  const res = await fetch(`https://api.cpfhub.io/cpf/${cpf.replace(/\D/g, '')}`, {
    headers: { 'x-api-key': process.env.CPFHUB_API_KEY! },
  })
  return { status: res.status, body: await res.json() }
}

const cpfTool = tool(
  async ({ cpf }) => {
    const { status, body } = await lookupCpf(cpf)
    if (status === 404) return 'CPF not found. Ask the user to check what they typed.'
    if (status !== 200) return `Error ${status} while looking up the CPF.`
    return `Name: ${body.data.name}, Date of birth: ${body.data.birthDate}`
  },
  {
    name: 'lookup_cpf',
    description: 'Looks up data for a person from their Brazilian CPF.',
    schema: z.object({
      cpf: z.string().describe('Brazilian CPF with or without formatting'),
    }),
  }
)

const llm = new ChatOpenAI({ model: 'gpt-4o' }).bindTools([cpfTool])

Vercel AI SDK

TypeScript
import { openai } from '@ai-sdk/openai'
import { generateText, stepCountIs, tool } from 'ai'
import { z } from 'zod'
async function lookupCpf(cpf: string) {
  const res = await fetch(`https://api.cpfhub.io/cpf/${cpf.replace(/\D/g, '')}`, {
    headers: { 'x-api-key': process.env.CPFHUB_API_KEY! },
  })
  if (res.status === 404) return { found: false }
  const body = await res.json()
  if (!res.ok) return { error: typeof body.error === 'string' ? body.error : body.error?.message }
  return { found: true, ...body.data }
}

const result = await generateText({
  model: openai('gpt-4o'),
  tools: {
    lookup_cpf: tool({
      description: 'Looks up data for a person from their Brazilian CPF.',
      inputSchema: z.object({
        cpf: z.string().describe('Brazilian CPF with or without formatting'),
      }),
      execute: async ({ cpf }) => lookupCpf(cpf),
    }),
  },
  stopWhen: stepCountIs(3), // lets the model call the tool and then answer
  prompt: 'Verify the identity for CPF 12345678909',
})

console.log(result.text)

Claude Desktop through MCP

To use it in Claude Desktop with no code, add the MCP Server as a connector under Settings > Connectors > Add custom connector, with the URL https://api.cpfhub.io/mcp?api_key=YOUR_API_KEY. See the step-by-step guide and the Claude Code and Cursor setup in MCP Server.


Updated on October 3, 2026