Limites e boas práticas
Limite de requisições por rota, como repetir chamadas com segurança, idempotência, tempo limite e quando usar webhooks em vez de consultar.
A API protege a loja contra excesso de chamadas e contra tentativas de adivinhar senhas. Esta página mostra os limites que existem de fato, e reúne as práticas que fazem uma integração se comportar bem: repetir só o que é seguro, não duplicar pedidos, não consultar à toa.
Limites de requisições
Os valores abaixo são o padrão da plataforma. Eles se aplicam por prefixo de rota e por IP de origem (o IP real do cliente, mesmo atrás de um proxy).
| Grupo de rotas | Limite | Janela |
|---|---|---|
/api/v1/auth/login | 5 | 1 minuto |
/api/v1/auth/register, forgot-password, reset-password | 3 cada | 1 minuto |
Demais rotas /api/v1/auth/ (como refresh) | 10 | 1 minuto |
/api/v1/admin/ | 1200 | 1 minuto |
/api/v1/vendor/ (painel do seller) | 100 | 1 minuto |
/api/v1/platform/ | 200 | 1 minuto |
/api/v1/webhooks/ | 60 | 1 minuto |
/api/v1/storefront/ (vitrine) | 600 (alguns subgrupos têm limite próprio) | 1 minuto |
Como o balde funciona
Cada grupo tem um balde com a capacidade do limite (1200, por exemplo) que se reabastece de forma contínua (1200 por minuto são 20 por segundo). Isso permite rajadas: você pode fazer 1200 chamadas de uma vez se o balde está cheio, e depois só o que reabastece. O que importa é o ritmo médio.
Como o limite é por IP, várias integrações que saem do mesmo endereço (a mesma rede, o mesmo NAT, o mesmo servidor) dividem o mesmo balde.
Quando passa do limite
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{"error":"rate limit exceeded","detail":"too many requests, please try again later"}O Retry-After vale 60 segundos. Espere esse tempo (ou use espera crescente, veja adiante) antes de tentar de novo.
Bloqueio de conta no login
Além do limite por IP, errar a senha várias vezes bloqueia aquele login por um tempo, mesmo com outra senha certa. A resposta é 429 com {"error":"account_locked"} e Retry-After em segundos. A quantidade de tentativas e o tempo de bloqueio são configurações da loja. Só erros de credencial contam: e-mail não verificado ou conta aguardando aprovação não bloqueiam.
Chaves da vitrine
As chaves sfk_... têm um limite próprio por minuto, definido ao criá-las (o padrão sugerido no painel é 100). Estourado, a resposta é 429 com {"error":"rate_limit_exceeded"} e Retry-After: 60.
Repetir chamadas com segurança
Uma chamada pode falhar sem que você saiba se a plataforma chegou a executá-la (a rede caiu depois do envio, o tempo acabou). Repetir às cegas pode duplicar um pedido. A regra:
| Tipo de chamada | Repetir? |
|---|---|
GET | Sempre seguro. |
PUT e DELETE com o mesmo resultado final | Em geral seguro (alterar para o mesmo valor, cancelar de novo). |
POST que cria algo | Só com idempotência, ou depois de conferir que o registro não existe. |
Resposta 400, 403, 404, 422 | Não adianta repetir sem mudar algo. |
Idempotência
Idempotente quer dizer que repetir a mesma chamada não muda o resultado além da primeira vez. A plataforma oferece isso em dois lugares:
- Pedido pela API administrativa (
POST /api/v1/admin/orders): envie o campoidempotency_keyno corpo, com um valor seu e único por pedido (o número do pedido no seu ERP é ideal). Mandar a mesma chave para o mesmo cliente devolve o pedido que já foi criado, em vez de criar outro. Veja Criar pedido. - Checkout da vitrine: o cabeçalho
Idempotency-Key(um UUID por tentativa de compra). Repetir a chamada devolve a resposta da primeira; se a primeira ainda está em andamento, a resposta é409com{"error":"in_progress","retry_after_ms":1500}.
Nas demais criações (clientes, produtos), não há chave de idempotência. Se uma criação deu timeout, consulte antes de repetir: por exemplo, procure o cliente pelo e-mail.
Espera crescente
Para 429, 503 e 5xx, repita com espera crescente e aleatória (backoff exponencial com jitter): 1 s, 2 s, 4 s, 8 s, cada uma com uma variação aleatória, até um teto de tentativas (por exemplo 5). Respeite o Retry-After quando vier. Para falhas de rede, a mesma estratégia.
import random, time, requests
def get_with_retry(url, headers, tries=5):
for attempt in range(tries):
r = requests.get(url, headers=headers, timeout=30)
if r.status_code not in (429, 503) and r.status_code < 500:
return r
wait = float(r.headers.get("Retry-After", 2 ** attempt)) + random.random()
time.sleep(wait)
return rTempo limite
Defina sempre um tempo limite no seu cliente (30 segundos é um bom começo para leituras e escritas simples; operações em lote pedem mais). Algumas rotas têm um teto no servidor e respondem 503 com {"error":"request timeout","code":"handler_timeout"}; trate como erro repetível.
Consultar menos
- Varreduras incrementais. Para importar pedidos, guarde a data do último processado e use o filtro de data com ordenação crescente; descarte duplicados pelo id. Não releia o histórico inteiro a cada ciclo.
- Páginas grandes. Use
per_page=100em vez de várias páginas pequenas. - Cache de cadastros. Formas de pagamento, métodos de frete e o cadastro de status mudam raramente: leia uma vez e renove de vez em quando.
- Webhooks no lugar de polling. Em vez de listar pedidos a cada minuto para saber o que mudou, cadastre um webhook e seja avisado do evento. Veja os fundamentos.
Segurança
- Guarde
access_token,refresh_token, token de app e chave da vitrine no servidor. Nunca em código de navegador, em app instalado no aparelho do cliente, em repositório ou em log. - Crie um usuário só para a integração, com os privilégios mínimos. Quando alguém sai da equipe, a senha dele não derruba a integração.
- Troque as credenciais com uma rotina: a senha pode ser trocada e o token de app revogado.
- Use
httpssempre. - Remova credenciais e dados pessoais dos logs. Registre o
X-Request-Id, que não é sensível.
Erros comuns
- Fazer login a cada requisição, estourando o limite de 5 por minuto.
- Paralelizar demais com o mesmo IP e ser limitado por causa de outra integração.
- Repetir um
POSTde criação semidempotency_key. - Retentar
400em loop. - Esquecer o tempo limite e deixar o processo preso.