Rate Limits
A API FluxiQ NPC implementa limites de requisicoes para garantir estabilidade e disponibilidade para todos os clientes.
Limites por Endpoint
Cada endpoint possui limites especificos baseados em sua natureza e impacto no sistema:
| Endpoint | Metodo | Limite | Janela | Descricao |
|---|---|---|---|---|
POST /boletos | POST | 100 req | 1 minuto | Criacao de boletos |
GET /boletos | GET | 1.000 req | 1 minuto | Listagem de boletos |
GET /boletos/:nosso_numero | GET | 1.000 req | 1 minuto | Consulta de boleto |
PATCH /boletos/:nosso_numero | PATCH | 100 req | 1 minuto | Atualizacao de boleto |
DELETE /boletos/:nosso_numero | DELETE | 100 req | 1 minuto | Cancelamento de boleto |
POST /boletos/:nosso_numero/pay | POST | 100 req | 1 minuto | Marcar como pago |
GET /settlements | GET | 1.000 req | 1 minuto | Listagem de liquidacoes |
GET /settlements/:id | GET | 1.000 req | 1 minuto | Consulta de liquidacao |
POST /settlements/trigger | POST | 10 req | 1 hora | Disparo manual de processamento |
GET /health | GET | 1.000 req | 1 minuto | Health check |
Endpoint de Trigger
O endpoint POST /settlements/trigger possui um limite muito restritivo (10 req/hora) pois dispara processamento intensivo. Use apenas quando necessario.
Headers de Rate Limit
Todas as respostas incluem headers que informam o estado atual do seu limite:
| Header | Tipo | Descricao |
|---|---|---|
X-RateLimit-Limit | integer | Numero maximo de requisicoes permitidas |
X-RateLimit-Remaining | integer | Numero de requisicoes restantes na janela atual |
X-RateLimit-Reset | integer | Timestamp Unix de quando o limite sera resetado |
Exemplo de Headers
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1706968800Interpretacao:
- Limite de 100 requisicoes por minuto
- Restam 87 requisicoes
- O limite reseta em
1706968800(timestamp Unix)
Resposta de Rate Limit Excedido
Quando o limite e excedido, a API retorna status 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1706968800
Retry-After: 45{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Limite de requisicoes excedido",
"details": "Aguarde 45 segundos antes de fazer novas requisicoes"
},
"meta": {
"request_id": "req_abc123def456"
}
}O header Retry-After indica quantos segundos voce deve aguardar antes de tentar novamente.
Implementacao de Retry
JavaScript com Exponential Backoff
class PixConnectClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = "https://api.pixconnect.com.br/api/v1/central";
this.maxRetries = 5;
this.baseDelay = 1000; // 1 segundo
}
async request(method, path, body = null, retryCount = 0) {
const url = `${this.baseUrl}${path}`;
const options = {
method,
headers: {
"X-API-Key": this.apiKey,
"Content-Type": "application/json",
},
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetch(url, options);
// Monitorar headers de rate limit
const remaining = response.headers.get("X-RateLimit-Remaining");
const limit = response.headers.get("X-RateLimit-Limit");
if (remaining !== null) {
console.log(`Rate limit: ${remaining}/${limit} restantes`);
// Alerta quando restam poucas requisicoes
if (parseInt(remaining) < parseInt(limit) * 0.1) {
console.warn("Atencao: Proximo do limite de requisicoes!");
}
}
// Tratar rate limit
if (response.status === 429) {
if (retryCount >= this.maxRetries) {
throw new Error("Limite de retries excedido");
}
const retryAfter = response.headers.get("Retry-After");
const delay = retryAfter
? parseInt(retryAfter) * 1000
: this.baseDelay * Math.pow(2, retryCount);
console.log(`Rate limited. Aguardando ${delay/1000}s (tentativa ${retryCount + 1}/${this.maxRetries})`);
await this.sleep(delay);
return this.request(method, path, body, retryCount + 1);
}
// Tratar erros de servidor com retry
if (response.status >= 500) {
if (retryCount >= this.maxRetries) {
const data = await response.json();
throw new Error(`Erro do servidor: ${data.error.message}`);
}
const delay = this.baseDelay * Math.pow(2, retryCount);
console.log(`Erro do servidor. Aguardando ${delay/1000}s (tentativa ${retryCount + 1}/${this.maxRetries})`);
await this.sleep(delay);
return this.request(method, path, body, retryCount + 1);
}
return response.json();
} catch (error) {
if (error.name === "TypeError" && retryCount < this.maxRetries) {
// Erro de rede - tentar novamente
const delay = this.baseDelay * Math.pow(2, retryCount);
console.log(`Erro de rede. Aguardando ${delay/1000}s`);
await this.sleep(delay);
return this.request(method, path, body, retryCount + 1);
}
throw error;
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Metodos de conveniencia
async createBoleto(boleto) {
return this.request("POST", "/boletos", { boleto });
}
async getBoleto(nossoNumero) {
return this.request("GET", `/boletos/${nossoNumero}`);
}
async listBoletos(params = {}) {
const query = new URLSearchParams(params).toString();
return this.request("GET", `/boletos?${query}`);
}
}
// Uso
const client = new PixConnectClient(process.env.PIXCONNECT_API_KEY);
const result = await client.createBoleto({
nosso_numero: "12345678901",
amount_cents: 15000,
due_date: "2026-03-15",
payer_document: "12345678901",
payer_name: "Joao Silva",
beneficiary_ispb: "02992335",
beneficiary_name: "Empresa XYZ"
});Python com Exponential Backoff
import requests
import time
import os
from typing import Optional, Dict, Any
class PixConnectClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.pixconnect.com.br/api/v1/central"
self.max_retries = 5
self.base_delay = 1.0 # 1 segundo
self.session = requests.Session()
self.session.headers.update({
"X-API-Key": api_key,
"Content-Type": "application/json"
})
def request(
self,
method: str,
path: str,
json: Optional[Dict] = None,
retry_count: int = 0
) -> Dict[str, Any]:
url = f"{self.base_url}{path}"
try:
response = self.session.request(method, url, json=json)
# Monitorar headers de rate limit
remaining = response.headers.get("X-RateLimit-Remaining")
limit = response.headers.get("X-RateLimit-Limit")
if remaining is not None:
print(f"Rate limit: {remaining}/{limit} restantes")
# Alerta quando restam poucas requisicoes
if int(remaining) < int(limit) * 0.1:
print("Atencao: Proximo do limite de requisicoes!")
# Tratar rate limit
if response.status_code == 429:
if retry_count >= self.max_retries:
raise Exception("Limite de retries excedido")
retry_after = response.headers.get("Retry-After")
delay = (
float(retry_after) if retry_after
else self.base_delay * (2 ** retry_count)
)
print(f"Rate limited. Aguardando {delay}s (tentativa {retry_count + 1}/{self.max_retries})")
time.sleep(delay)
return self.request(method, path, json, retry_count + 1)
# Tratar erros de servidor com retry
if response.status_code >= 500:
if retry_count >= self.max_retries:
data = response.json()
raise Exception(f"Erro do servidor: {data['error']['message']}")
delay = self.base_delay * (2 ** retry_count)
print(f"Erro do servidor. Aguardando {delay}s (tentativa {retry_count + 1}/{self.max_retries})")
time.sleep(delay)
return self.request(method, path, json, retry_count + 1)
return response.json()
except requests.exceptions.RequestException as e:
if retry_count < self.max_retries:
delay = self.base_delay * (2 ** retry_count)
print(f"Erro de rede. Aguardando {delay}s")
time.sleep(delay)
return self.request(method, path, json, retry_count + 1)
raise
# Metodos de conveniencia
def create_boleto(self, boleto: Dict) -> Dict:
return self.request("POST", "/boletos", {"boleto": boleto})
def get_boleto(self, nosso_numero: str) -> Dict:
return self.request("GET", f"/boletos/{nosso_numero}")
def list_boletos(self, **params) -> Dict:
query = "&".join(f"{k}={v}" for k, v in params.items())
path = f"/boletos?{query}" if query else "/boletos"
return self.request("GET", path)
# Uso
client = PixConnectClient(os.environ["PIXCONNECT_API_KEY"])
result = client.create_boleto({
"nosso_numero": "12345678901",
"amount_cents": 15000,
"due_date": "2026-03-15",
"payer_document": "12345678901",
"payer_name": "Joao Silva",
"beneficiary_ispb": "02992335",
"beneficiary_name": "Empresa XYZ"
})Boas Praticas
1. Monitore os Headers
Sempre verifique os headers X-RateLimit-Remaining e ajuste sua taxa de requisicoes proativamente:
if (remaining < limit * 0.2) {
// Restam menos de 20% - reduzir velocidade
await sleep(1000);
}2. Implemente Exponential Backoff
Quando receber erro 429 ou 5xx, use backoff exponencial:
Tentativa 1: 1 segundo
Tentativa 2: 2 segundos
Tentativa 3: 4 segundos
Tentativa 4: 8 segundos
Tentativa 5: 16 segundosJitter
Adicione um pequeno valor aleatorio (jitter) ao delay para evitar que multiplos clientes retry no mesmo instante:
const jitter = Math.random() * 1000;
const delay = baseDelay * Math.pow(2, retryCount) + jitter;3. Circuit Breaker Pattern
Para sistemas de alta disponibilidade, implemente um circuit breaker:
class CircuitBreaker {
constructor(threshold = 5, timeout = 30000) {
this.failures = 0;
this.threshold = threshold;
this.timeout = timeout;
this.state = "CLOSED"; // CLOSED, OPEN, HALF_OPEN
this.lastFailure = null;
}
async execute(fn) {
if (this.state === "OPEN") {
if (Date.now() - this.lastFailure > this.timeout) {
this.state = "HALF_OPEN";
} else {
throw new Error("Circuit breaker is OPEN");
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failures = 0;
this.state = "CLOSED";
}
onFailure() {
this.failures++;
this.lastFailure = Date.now();
if (this.failures >= this.threshold) {
this.state = "OPEN";
}
}
}
// Uso
const breaker = new CircuitBreaker();
try {
const result = await breaker.execute(() =>
client.createBoleto(boletoData)
);
} catch (error) {
if (error.message === "Circuit breaker is OPEN") {
// Servico temporariamente indisponivel
// Usar fallback ou notificar usuario
}
}4. Agrupe Requisicoes
Quando possivel, agrupe operacoes para reduzir o numero de requisicoes:
// Evite: multiplas requisicoes individuais
for (const id of boletoIds) {
await client.getBoleto(id); // Muitas requisicoes!
}
// Prefira: usar listagem com filtros
const result = await client.listBoletos({
nosso_numero: boletoIds.join(","),
limit: 100
});5. Cache de Leitura
Implemente cache para requisicoes GET frequentes:
const cache = new Map();
const CACHE_TTL = 60000; // 1 minuto
async function getBoletoWithCache(nossoNumero) {
const cacheKey = `boleto:${nossoNumero}`;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const result = await client.getBoleto(nossoNumero);
cache.set(cacheKey, {
data: result.data,
timestamp: Date.now()
});
return result.data;
}Limites por Ambiente
Os limites variam de acordo com o ambiente:
| Ambiente | Multiplicador | POST /boletos | GET endpoints | POST /settlements/trigger |
|---|---|---|---|---|
| Producao | 1x | 100/min | 1.000/min | 10/hora |
| Sandbox | 0.1x | 10/min | 100/min | 1/hora |
| Local | Ilimitado | - | - | - |
Ambiente de Testes
O ambiente sandbox possui limites reduzidos para evitar uso excessivo durante desenvolvimento. Para testes de carga, entre em contato com o suporte.
Solicitar Aumento de Limite
Se os limites atuais nao atendem sua demanda, voce pode solicitar um aumento:
Requisitos
- Conta em producao ativa por pelo menos 30 dias
- Historico de uso demonstrando necessidade
- Caso de uso justificado
Processo de Solicitacao
- Acesse o FluxiQ Portal
- Navegue para Configuracoes > API > Rate Limits
- Clique em Solicitar Aumento
- Preencha o formulario com:
- Endpoint(s) que precisam de aumento
- Limite desejado
- Justificativa tecnica
- Volume esperado de transacoes
SLA de Resposta
| Tipo de Conta | Tempo de Resposta |
|---|---|
| Enterprise | 1 dia util |
| Business | 3 dias uteis |
| Standard | 5 dias uteis |
Dica
Antes de solicitar aumento, revise suas implementacoes para garantir que voce esta utilizando as melhores praticas descritas nesta pagina. Muitas vezes, otimizacoes no codigo podem resolver problemas de rate limit.
Proximos Passos
- Codigos de Erro - Entenda todos os erros possiveis
- Autenticacao - Configurar API Key
- Ambientes - Testar em sandbox