Pular para o conteúdo principal

Políticas de Rate Limit

A API do TapSign limita a quantidade de requisições para manter o serviço estável e disponível para todos.

Limite por chave de API​

Requisições autenticadas com chave de API (Authorization: Bearer tsk_...) podem fazer 60 requisições por minuto por chave, somando todas as rotas. O limite é o mesmo em todos os planos.

AmbienteLimite por chave
Produção60 requisições/minuto
Sandbox120 requisições/minuto
Como a janela funciona

A cota da chave é renovada por inteiro a cada minuto. Não é uma janela deslizante: se você gastar as 60 requisições nos primeiros segundos, as próximas recebem 429 até a cota ser renovada.

Rotas com limite menor​

Algumas rotas têm um teto próprio, que também vale para chaves de API. Nelas a requisição precisa caber nos dois limites: o da chave e o da rota.

RotaLimite
POST /v1/webhooks/{webhookId}/logs/{logId}/retry10 requisições/minuto
GET /v1/models/{id}/pdf-preview10 requisições/minuto

Requisições sem chave de API​

Requisições com token JWT, ou em rotas públicas, são limitadas por IP, com um contador por tipo de requisição. Em produção:

RequisiçãoLimite por IP
GET400/minuto
POST40/minuto
PUT e PATCH80/minuto
DELETE20/minuto
POST /v1/auth/api/token5/minuto
POST /v1/auth/api/token-refresh10/minuto
GET /v1/webhooks/{webhookId}/logs60/minuto
POST /v1/webhooks/{webhookId}/logs/{logId}/retry10/minuto
GET /v1/models/{id}/pdf-preview10/minuto

No sandbox esses limites são mais altos (veja Ambiente de Testes).

Use chave de API na integração

Com chave de API, o limite é da chave e não depende do IP. Com JWT, todas as chamadas que saem do mesmo IP dividem os mesmos contadores.

Headers de Rate Limit​

As respostas trazem o estado da cota que se aplica à requisição:

HeaderDescriçãoExemplo
X-Rate-Limit-LimitTamanho da cota que se aplica à requisição60
X-Rate-Limit-RemainingRequisições que ainda cabem na cota atual59
Retry-AfterSó na resposta 429: segundos para tentar de novo60

Não existe header com o horário de renovação da cota. Em rotas com limite próprio, os headers mostram a cota mais apertada no momento (a da chave ou a da rota).

Exemplo de headers em uma resposta​

HTTP/2 200
content-type: application/json
x-rate-limit-limit: 60
x-rate-limit-remaining: 59

Resposta 429: rate limit excedido​

Quando a cota acaba, a API responde 429 Too Many Requests:

HTTP/2 429
content-type: application/json
x-rate-limit-limit: 60
x-rate-limit-remaining: 0
retry-after: 60
{
"title": "Rate limit exceeded!",
"status": 429,
"details": "Too many requests. Please wait a moment and try again.",
"timestamp": "2026-09-12T14:31:05Z",
"devMsg": "RateLimitFilter: Too many requests. Please retry after the Retry-After period.",
"fields": {}
}

Com o header Accept-Language: pt-BR, title e details vêm em português ("Limite de requisições excedido!" e "Muitas requisições. Por favor, aguarde um momento e tente novamente.").

Atenção

Requisições que recebem 429 não são processadas. Reenvie depois de aguardar o tempo indicado em Retry-After.

Boas práticas​

1. Monitore os headers​

Acompanhe X-Rate-Limit-Remaining para desacelerar antes de chegar a zero.

async function callTapSignAPI(url, options) {
const response = await fetch(url, options);

const remaining = Number(response.headers.get('X-Rate-Limit-Remaining'));
if (remaining < 10) {
console.warn(`Rate limit baixo: ${remaining} requisições restantes`);
}

return response;
}

2. Implemente retry com espera​

Ao receber 429, espere o tempo de Retry-After antes de reenviar. Sem o header, use backoff exponencial:

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);

if (response.status !== 429) {
return response;
}

if (attempt === maxRetries) {
throw new Error('Rate limit excedido após várias tentativas');
}

const retryAfter = response.headers.get('Retry-After');
const waitMs = retryAfter
? Number(retryAfter) * 1000
: Math.pow(2, attempt) * 1000 + Math.random() * 1000;

console.log(`Rate limit atingido. Aguardando ${waitMs} ms...`);
await new Promise(resolve => setTimeout(resolve, waitMs));
}
}
import time
import random
import requests

def fetch_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries + 1):
response = requests.get(url, headers=headers)

if response.status_code != 429:
return response

if attempt == max_retries:
raise Exception("Rate limit excedido após várias tentativas")

retry_after = response.headers.get("Retry-After")
wait_time = int(retry_after) if retry_after else (2 ** attempt) + random.uniform(0, 1)

print(f"Rate limit atingido. Aguardando {wait_time}s...")
time.sleep(wait_time)

3. Distribua as requisições​

Evite rajadas. Com 60 requisições por minuto, processe em lotes pequenos com intervalo:

const headers = { Authorization: `Bearer ${process.env.TAPSIGN_API_KEY}` };

// Ruim: 100 requisições simultâneas estouram a cota
await Promise.all(ids.map(id => fetch(`https://api.tapsign.com.br/v1/envelopes/${id}`, { headers })));

// Bom: lotes de 10 a cada 10 segundos (60 por minuto)
async function processInBatches(ids, batchSize = 10, delayMs = 10000) {
const results = [];
for (let i = 0; i < ids.length; i += batchSize) {
const batch = ids.slice(i, i + batchSize);
const batchResults = await Promise.all(
batch.map(id => fetch(`https://api.tapsign.com.br/v1/envelopes/${id}`, { headers }))
);
results.push(...batchResults);

if (i + batchSize < ids.length) {
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
return results;
}

4. Use webhooks em vez de polling​

Em vez de consultar o status de um envelope repetidamente, configure webhooks para ser avisado quando algo mudar.

Dica

Webhooks não consomem o seu rate limit: é o TapSign que chama a sua aplicação.

5. Faça cache de respostas​

Para dados que mudam pouco (como a lista de modelos), guarde a resposta localmente e evite requisições repetidas.


Próxima seção: Status de Erros: entenda as respostas de erro da API.