Para implementar multi-tenancy com API de CPF em plataformas SaaS, o caminho é criar uma camada intermediária que isola o consumo por tenant, controla limites individuais e centraliza a chave de API no backend. Cada tenant opera com seu próprio namespace no cache, registro de consumo e faturamento proporcional. A OWASP recomenda que chaves de API nunca sejam expostas ao cliente final — a arquitetura de middleware resolve exatamente isso.
Desafios do multi-tenancy com APIs externas
Controle de consumo
Quando múltiplos tenants compartilham uma única chave de API, é necessário rastrear quantas consultas cada um realizou para fins de faturamento e limites.
Isolamento de dados
Os resultados de consulta de um tenant não devem ser acessíveis por outro. Mesmo que o cache seja compartilhado, as chaves devem incluir o identificador do tenant.
Limites diferenciados
Cada tenant pode ter um plano diferente dentro da sua plataforma SaaS, com limites de consultas distintos.
Faturamento proporcional
O custo das consultas à API precisa ser repassado (total ou parcialmente) para cada tenant com base no seu consumo real.
Arquitetura proposta
A solução consiste em uma camada intermediária (middleware) entre os tenants e a API da CPFHub.io.
Componentes
-
Middleware de controle -- Recebe as requisições dos tenants, verifica limites e encaminha para a API.
-
Banco de dados -- Armazena os limites e o consumo de cada tenant.
-
Cache compartilhado -- Redis com chaves prefixadas pelo tenant ID para isolamento.
-
Módulo de faturamento -- Contabiliza o consumo para cobrança.
Implementação em Python com Flask
import requests
import redis
import json
from flask import Flask, request, jsonify
from datetime import datetime
app = Flask(__name__)
redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
CPFHUB_API_KEY = 'SUA_CHAVE_DE_API'
# Configuracao de limites por tenant (em producao, vem do banco de dados)
TENANT_LIMITES = {
'tenant_001': {'limite_mensal': 500, 'plano': 'basico'},
'tenant_002': {'limite_mensal': 2000, 'plano': 'premium'},
'tenant_003': {'limite_mensal': 100, 'plano': 'trial'}
}
def obter_consumo_mensal(tenant_id: str) -> int:
mes_atual = datetime.now().strftime('%Y-%m')
chave = f'cpfhub:consumo:{tenant_id}:{mes_atual}'
consumo = redis_client.get(chave)
return int(consumo) if consumo else 0
def incrementar_consumo(tenant_id: str):
mes_atual = datetime.now().strftime('%Y-%m')
chave = f'cpfhub:consumo:{tenant_id}:{mes_atual}'
redis_client.incr(chave)
# Expirar no final do mes seguinte
redis_client.expire(chave, 60 * 60 * 24 * 35)
def verificar_limite(tenant_id: str) -> bool:
config = TENANT_LIMITES.get(tenant_id)
if not config:
return False
consumo = obter_consumo_mensal(tenant_id)
return consumo < config['limite_mensal']
@app.route('/api/cpf/<cpf>')
def consultar_cpf(cpf):
# 1. Identificar tenant
tenant_id = request.headers.get('X-Tenant-ID')
if not tenant_id:
return jsonify({'error': 'Header X-Tenant-ID obrigatorio'}), 400
if tenant_id not in TENANT_LIMITES:
return jsonify({'error': 'Tenant nao encontrado'}), 404
# 2. Verificar limite
if not verificar_limite(tenant_id):
return jsonify({
'error': 'Limite de consultas excedido',
'consumo': obter_consumo_mensal(tenant_id),
'limite': TENANT_LIMITES[tenant_id]['limite_mensal']
}), 429
# 3. Verificar cache (isolado por tenant)
chave_cache = f'cpfhub:cache:{tenant_id}:{cpf}'
cacheado = redis_client.get(chave_cache)
if cacheado:
return jsonify(json.loads(cacheado))
# 4. Consultar API
url = f'https://api.cpfhub.io/cpf/{cpf}'
headers = {
'x-api-key': CPFHUB_API_KEY,
'Accept': 'application/json'
}
try:
response = requests.get(url, headers=headers, timeout=10)
resultado = response.json()
if resultado.get('success'):
# Cachear por 1 hora
redis_client.setex(chave_cache, 3600, json.dumps(resultado))
# Incrementar consumo
incrementar_consumo(tenant_id)
return jsonify(resultado)
except requests.exceptions.Timeout:
return jsonify({'error': 'Timeout na consulta'}), 504
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/consumo')
def obter_consumo():
tenant_id = request.headers.get('X-Tenant-ID')
if not tenant_id:
return jsonify({'error': 'Header X-Tenant-ID obrigatorio'}), 400
config = TENANT_LIMITES.get(tenant_id, {})
consumo = obter_consumo_mensal(tenant_id)
return jsonify({
'tenant_id': tenant_id,
'consumo_atual': consumo,
'limite_mensal': config.get('limite_mensal', 0),
'restante': max(0, config.get('limite_mensal', 0) - consumo),
'plano': config.get('plano', 'desconhecido')
})
if __name__ == '__main__':
app.run(port=5000)
Controle de consumo em Node.js
const express = require('express');
const Redis = require('ioredis');
const app = express();
const redis = new Redis();
const CPFHUB_API_KEY = 'SUA_CHAVE_DE_API';
async function verificarLimite(tenantId, limiteMensal) {
const mesAtual = new Date().toISOString().slice(0, 7);
const chave = `cpfhub:consumo:${tenantId}:${mesAtual}`;
const consumo = parseInt(await redis.get(chave) || '0');
return consumo < limiteMensal;
}
async function incrementarConsumo(tenantId) {
const mesAtual = new Date().toISOString().slice(0, 7);
const chave = `cpfhub:consumo:${tenantId}:${mesAtual}`;
await redis.incr(chave);
await redis.expire(chave, 60 * 60 * 24 * 35);
}
app.get('/api/cpf/:cpf', async (req, res) => {
const tenantId = req.headers['x-tenant-id'];
if (!tenantId) {
return res.status(400).json({ error: 'Header X-Tenant-ID obrigatorio' });
}
const podeContinuar = await verificarLimite(tenantId, 500);
if (!podeContinuar) {
return res.status(429).json({ error: 'Limite de consultas excedido' });
}
const { cpf } = req.params;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(
`https://api.cpfhub.io/cpf/${cpf}`,
{
headers: {
'x-api-key': CPFHUB_API_KEY,
'Accept': 'application/json'
},
signal: controller.signal
}
);
clearTimeout(timeoutId);
const resultado = await response.json();
await incrementarConsumo(tenantId);
return res.json(resultado);
} catch (error) {
clearTimeout(timeoutId);
return res.status(500).json({ error: 'Erro na consulta' });
}
});
app.listen(3000);
Estratégias de faturamento
| Modelo | Descrição | Melhor para |
|---|---|---|
| Incluso no plano | Cada plano SaaS inclui X consultas | Simplicidade |
| Pay-per-use | Cobrar por consulta realizada | Transparência |
| Créditos | Tenant compra pacotes de créditos | Flexibilidade |
| Híbrido | Base inclusa + excedente cobrado à parte | Previsibilidade com elasticidade |
Boas práticas
-
Isole o cache por tenant -- Use o tenant ID como prefixo nas chaves do Redis para evitar vazamento de dados entre clientes.
-
Registre cada consulta -- Mantenha um log detalhado com tenant ID, CPF consultado (ou hash), timestamp e resultado para auditoria e faturamento.
-
Implemente alertas de consumo -- Notifique o tenant quando ele atingir 80% e 100% do limite mensal.
-
Considere o plano Corporativo -- Para plataformas SaaS com alto volume de consultas distribuídas entre múltiplos tenants, o plano Corporativo da CPFHub.io oferece limites personalizados e SLA de 99,9%.
-
Centralize a chave de API -- Use uma única chave de API no backend da sua plataforma. Nunca exponha a chave aos tenants.
Perguntas frequentes
Como funciona o isolamento de dados entre tenants ao usar uma API de CPF compartilhada?
O isolamento é feito prefixando todas as chaves de cache e registro com o tenant ID. No Redis, uma chave como cpfhub:cache:tenant_001:12345678900 garante que o resultado da consulta de um tenant nunca seja servido a outro, mesmo que o CPF seja idêntico. Cada tenant enxerga apenas seu próprio consumo e seus próprios resultados.
O que acontece se um tenant ultrapassar o limite de consultas da minha plataforma SaaS?
O middleware deve retornar HTTP 429 para o tenant antes de sequer acionar a API externa. Isso protege seu orçamento e mantém a equidade entre clientes. No plano gratuito da CPFHub.io, 50 consultas mensais são incluídas sem cartão — consultas adicionais custam R$0,15 cada, sem bloqueio automático da API.
Qual modelo de faturamento é mais indicado para SaaS com múltiplos tenants e volumes variáveis?
O modelo híbrido — base inclusa no plano + excedente cobrado à parte — costuma funcionar melhor. Ele dá previsibilidade ao tenant nos meses normais e elasticidade nos picos, sem que você absorva integralmente o custo extra. A CPFHub.io adota exatamente esse modelo: plano com cota inclusa e R$0,15 por consulta além do limite.
Como garantir conformidade com a LGPD ao repassar consultas de CPF entre tenants e a API?
Cada tenant é um controlador de dados independente. O middleware deve registrar a finalidade da consulta, o tenant solicitante e o timestamp, sem armazenar o CPF bruto além do necessário. A ANPD orienta que dados de identificação devem ser tratados com minimização e finalidade declarada — o log de consumo por tenant serve como evidência de rastreabilidade.
Conclusão
Implementar multi-tenancy para consultas de CPF em plataformas SaaS exige planejamento cuidadoso de controle de consumo, isolamento de dados e faturamento. Com uma camada intermediária bem construída e o Redis para controle de limites e cache, é possível oferecer essa funcionalidade de forma escalável e transparente. A CPFHub.io
Cadastre-se em cpfhub.io
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
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.



