Cobrança e limites
Créditos, dry-run, idempotência, rate limit, franquia diária de leituras e timeouts.
Modelo de créditos
- O saldo é exibido em créditos no dashboard, e todos os valores desta documentação estão em créditos.
- Operações pagas debitam na confirmação — nunca no dry-run.
- As regras de preço de cada ferramenta ficam na página da ferramenta: QR Dinâmico, PDF Convert, Base de conhecimento, Áudio.
- Cada token pode ter um limite diário de gasto: passar dele responde
billing.spend_limit_reached.
Preço exato
Custos de criação podem somar adicionais (slug customizado, design, retenção de PDF…). Faça um dry-run com o payload real para ver o total exato.
Dry-run e preview de custo
| Header | Efeito |
|---|---|
X-Dry-Run: true | Valida e calcula o custo sem persistir nem debitar |
X-Preview-Cost: true | Alias de X-Dry-Run |
X-Include-Cost: true | Inclui meta.cost na resposta |
Dry-run é aceito nas operações pagas marcadas no card de cada endpoint e nas leituras medidas (exceto downloads). A resposta é 200 e nada é persistido nem debitado.
As rotas de Áudio pedem o dry-run com ?dry_run=true na query, não com o header. O áudio é cobrado por minuto de áudio, por 1.000 caracteres ou por segundo gerado, e o valor da transcrição, da fala e dos demais jobs é devolvido se o motor falhar.
Orçamento de uma operação paga
Em POST de criação e conversão, data traz o orçamento item a item:
{
"success": true,
"trace_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"total_cost_credits": 15000,
"total_cost_units": 15000,
"items": [
{ "description": { "key": "billing.pdf.convert_base" }, "cost_credits": 10000, "type": "base" },
{ "description": { "key": "billing.pdf.retention.7" }, "cost_credits": 5000, "type": "storage" }
],
"is_monthly_recurring": false,
"currency": "CREDITS"
}
}Valores em unidades
Apesar do nome, total_cost_credits e cost_credits do orçamento (e cost_credits das conversões de PDF) vêm em unidades internas: divida por 10.000 para obter créditos. No exemplo, 15.000 unidades = 1,5 crédito.
No QR Dinâmico o orçamento também traz slot_usage (uso de slots e se a criação abrirá um novo slot pago) e recurring_cost.
Preview de uma leitura medida
Em leituras medidas, o dry-run não executa a consulta — mostra apenas a posição na franquia e se a leitura seria cobrada:
{
"success": true,
"trace_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"operation": "qr_dynamic.analytics",
"metering": {
"within_quota": true,
"quota_limit": 2000,
"quota_used": 125,
"quota_remaining": 1875,
"cost_units": 300,
"would_charge": false
}
},
"meta": {
"cost": {
"units": 300,
"credits": 0.03,
"charged": false,
"within_quota": true,
"quota_limit": 2000,
"quota_used": 125,
"quota_remaining": 1875
}
}
}Com X-Include-Cost: true numa leitura real, o mesmo objeto meta.cost acompanha a resposta normal (charged: true quando a leitura foi cobrada).
Idempotência
Envie X-Idempotency-Key (UUID recomendado) em qualquer rota de ferramentas:
- a chave vale por 24 horas;
- mesma chave + mesmo payload → a resposta original é reaproveitada, sem nova cobrança;
- mesma chave + payload diferente →
idempotency.conflict(409).
Use sempre em POST de criação e conversão para que retries de rede não cobrem duas vezes.
Exceção: as rotas da Base de conhecimento ignoram o header, porque já são idempotentes (conteúdo repetido não é reindexado nem cobrado).
Rate limit
Cada token de API pode fazer 60 requisições por minuto nas rotas /v1/tools/*. Toda resposta informa a situação:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1712345678Ao exceder, a API retorna rate_limit.exceeded (429). Aguarde até X-RateLimit-Reset antes de reenviar.
Repetir com espera (retry)
Repita só o que pode dar certo na tentativa seguinte:
429: espere até o horário deX-RateLimit-Reset(segundos Unix).5xxe falhas de rede: espere cada vez mais, com um pouco de aleatoriedade (backoff exponencial com jitter): cerca de 1 s, 2 s, 4 s… até 30 s, no máximo 5 tentativas.- Demais
4xx(validação, escopo, saldo): não repita. A resposta não muda até você corrigir a requisição.
Em POST que cria ou cobra algo, envie a mesma X-Idempotency-Key em todas as tentativas: se a primeira chegou e só a resposta se perdeu, a repetição devolve o resultado original sem cobrar de novo.
// Repete 429, 5xx e falhas de rede; devolve na hora os demais erros.
async function withRetry(send, attempts = 5) {
for (let attempt = 1; ; attempt++) {
let response;
try {
response = await send();
} catch (error) {
if (attempt === attempts) throw error; // falha de rede
}
if (response && response.status !== 429 && response.status < 500) return response;
if (attempt === attempts) return response;
const reset = Number(response?.headers.get('X-RateLimit-Reset'));
const wait =
response?.status === 429 && reset
? Math.max(0, reset * 1000 - Date.now())
: Math.min(2 ** (attempt - 1) * 1000, 30_000) * (0.5 + Math.random());
await new Promise((resolve) => setTimeout(resolve, wait));
}
}
const key = crypto.randomUUID(); // a mesma chave em todas as tentativas
const response = await withRetry(() =>
fetch(url, {
method: 'POST',
headers: {
'X-API-Token': process.env.RESPAWN_API_TOKEN,
'X-Idempotency-Key': key,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
}),
);import os, random, time, uuid
import requests
# Repete 429, 5xx e falhas de rede; devolve na hora os demais erros.
def with_retry(send, attempts=5):
for attempt in range(1, attempts + 1):
try:
response = send()
except (requests.ConnectionError, requests.Timeout):
if attempt == attempts:
raise
response = None
if response is not None and response.status_code != 429 and response.status_code < 500:
return response
if attempt == attempts:
return response
reset = response.headers.get("X-RateLimit-Reset") if response is not None else None
if response is not None and response.status_code == 429 and reset:
wait = max(0, int(reset) - time.time())
else:
wait = min(2 ** (attempt - 1), 30) * (0.5 + random.random())
time.sleep(wait)
key = str(uuid.uuid4()) # a mesma chave em todas as tentativas
response = with_retry(lambda: requests.post(
url,
json=payload,
headers={"X-API-Token": os.environ["RESPAWN_API_TOKEN"], "X-Idempotency-Key": key},
timeout=30,
))Franquia diária de leituras
Leituras feitas com token de API (listagens, status, analytics, downloads…) entram em uma franquia diária compartilhada entre todas as ferramentas:
| Item | Valor |
|---|---|
| Leituras grátis por dia | 2.000 |
| Contas premium | 4.000 |
| Reset | meia-noite UTC |
Toda leitura medida devolve a posição na franquia:
X-API-Quota-Limit: 2000
X-API-Quota-Used: 847
X-API-Quota-Remaining: 1153Requisições feitas pelo dashboard não entram na franquia nem são cobradas.
Leituras medidas
Depois de esgotar a franquia, cada leitura via API debita:
| Ferramenta | Operação | Créditos após a franquia |
|---|---|---|
| QR Dinâmico | GETListar QRs | 0,005 |
| QR Dinâmico | GETDetalhe | 0,01 |
| QR Dinâmico | GETVerificar disponibilidade de slug | 0,005 |
| QR Dinâmico | GETOverview de analytics | 0,03 |
| QR Dinâmico | GETScans por período | 0,03 |
| QR Dinâmico | GETDistribuição por dispositivo | 0,03 |
| QR Dinâmico | GETHistórico de scans | 0,01 |
| QR Dinâmico | GETExportar scans em CSV | 0,01 |
| QR Dinâmico | GETListar pastas | 0,005 |
| QR Dinâmico | GETListar lotes | 0,005 |
| QR Dinâmico | GETDetalhe do lote | 0,01 |
| PDF Convert | GETListar conversões | 0,005 |
| PDF Convert | GETStatus da conversão | 0,01 |
| PDF Convert | GETBaixar arquivo | 0,03 |
| PDF Convert | GETListar batches | 0,005 |
| PDF Convert | GETDetalhe do batch | 0,01 |
| PDF Convert | GETDownload ZIP do batch | 0,03 |
| Verificação de URL | GETVerificar URL | 0,01 |
| Verificação de URL | GETFavicon de um domínio | 0,002 |
| Webhook Relay | GETListar mensagens | 0,002 |
| Webhook Relay | GETConsultar mensagem | 0,002 |
| Realtime | GETConsultar histórico do canal | 0,002 |
| Extrator de erro de CI | POSTExtrair o erro de um log | 0,01 |
| Página web para Markdown | POSTConverter página em Markdown | 0,01 |
| Notificações | POSTEnviar notificação | 0,03 |
| Áudio | GETListar jobs de áudio | 0,005 |
| Áudio | GETStatus e resultado do job | 0,01 |
Operações de escrita sem custo próprio (PATCH, ativar, desativar, DELETE) e o dry-run de criação são sempre gratuitos.
Evite polling
A franquia cobre a maioria das integrações. Para acompanhar mudanças de estado, prefira webhooks em vez de consultar o status repetidamente.
Timeouts
- Maioria das rotas: 30 segundos.
- Downloads de arquivo: 2 minutos.
Atualizado em