Skip to content

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:

EndpointMetodoLimiteJanelaDescricao
POST /boletosPOST100 req1 minutoCriacao de boletos
GET /boletosGET1.000 req1 minutoListagem de boletos
GET /boletos/:nosso_numeroGET1.000 req1 minutoConsulta de boleto
PATCH /boletos/:nosso_numeroPATCH100 req1 minutoAtualizacao de boleto
DELETE /boletos/:nosso_numeroDELETE100 req1 minutoCancelamento de boleto
POST /boletos/:nosso_numero/payPOST100 req1 minutoMarcar como pago
GET /settlementsGET1.000 req1 minutoListagem de liquidacoes
GET /settlements/:idGET1.000 req1 minutoConsulta de liquidacao
POST /settlements/triggerPOST10 req1 horaDisparo manual de processamento
GET /healthGET1.000 req1 minutoHealth 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:

HeaderTipoDescricao
X-RateLimit-LimitintegerNumero maximo de requisicoes permitidas
X-RateLimit-RemainingintegerNumero de requisicoes restantes na janela atual
X-RateLimit-ResetintegerTimestamp Unix de quando o limite sera resetado

Exemplo de Headers

http
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1706968800

Interpretacao:

  • 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
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
json
{
  "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

javascript
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

python
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:

javascript
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 segundos

Jitter

Adicione um pequeno valor aleatorio (jitter) ao delay para evitar que multiplos clientes retry no mesmo instante:

javascript
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:

javascript
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:

javascript
// 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:

javascript
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:

AmbienteMultiplicadorPOST /boletosGET endpointsPOST /settlements/trigger
Producao1x100/min1.000/min10/hora
Sandbox0.1x10/min100/min1/hora
LocalIlimitado---

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

  1. Conta em producao ativa por pelo menos 30 dias
  2. Historico de uso demonstrando necessidade
  3. Caso de uso justificado

Processo de Solicitacao

  1. Acesse o FluxiQ Portal
  2. Navegue para Configuracoes > API > Rate Limits
  3. Clique em Solicitar Aumento
  4. Preencha o formulario com:
    • Endpoint(s) que precisam de aumento
    • Limite desejado
    • Justificativa tecnica
    • Volume esperado de transacoes

SLA de Resposta

Tipo de ContaTempo de Resposta
Enterprise1 dia util
Business3 dias uteis
Standard5 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

Documentação da API FluxiQ NPC