Tudo sobre

Paginação de API: Por Que sua Exportação Trava em 10 Mil Registros

Exportar 500 contatos é instantâneo, mas 500 mil trava. O culpado é o tipo de paginação da API: offset degrada com o tamanho da base, cursor não. Entenda a diferença e o que pedir ao fornecedor.

Exportar 500 contatos do CRM é instantâneo. Exportar 500 mil trava, dá timeout ou volta com erro genérico. A causa quase nunca é “muito dado” — é o tipo de paginação que a API usa para entregar resultados em pedaços. Existem duas famílias, e uma delas piora conforme a base cresce; a outra não.

Pense numa lista telefônica impressa. Se alguém pedir “me dê a página 400”, você folheia da capa até lá, contando página por página — quanto mais fundo no livro, mais tempo leva. Agora pense num marcador de página física: você abre exatamente onde parou da última vez, sem folhear nada antes. A primeira é paginação por offset; a segunda é paginação por cursor. A diferença de desempenho entre as duas é exatamente essa.

Como cada abordagem funciona

Toda API que devolve listas grandes — contatos, pedidos, eventos, produtos — precisa dividir o resultado em páginas. Como ela decide qual “pedaço” entregar a cada chamada é o que separa as duas famílias:

AbordagemComo é pedidaComo o servidor processaComportamento com a base crescendo
Offset / page?page=400&size=100Conta e descarta as 39.900 linhas anteriores antes de devolver as 100 pedidasDegrada — cada página fica mais lenta que a anterior
Cursor / keyset?cursor=xk29fA...Salta direto para o ponto marcado pelo cursor, sem varrer o que veio antesEstável — a página 4.000 custa o mesmo que a página 4

No offset, o banco de dados literalmente varre e descarta todas as linhas anteriores à página pedida, toda vez. Pedir a página 1 é barato. Pedir a página 5.000 exige que o banco percorra as 500 mil linhas anteriores antes de entregar as 100 que você realmente quer — e descartar 500 mil linhas não é grátis, mesmo que elas nunca cheguem até você.

No cursor, cada resposta vem com um “marcador” que aponta exatamente onde a próxima busca deve começar — geralmente baseado num identificador único e ordenado, como um ID crescente ou timestamp. A próxima chamada usa esse marcador para pular direto ao ponto certo, sem processar nada anterior. Não importa se você está na página 4 ou na página 40 mil: o custo de buscar a próxima leva de resultados é sempre o mesmo.

O sintoma reconhecível

Você não precisa entender a implementação para suspeitar do diagnóstico. O padrão é sempre o mesmo:

  • Exportar uma base pequena ou testar com poucos registros funciona perfeitamente rápido.
  • Ao crescer — mais contatos, mais pedidos, mais eventos — a mesma operação começa a demorar cada vez mais.
  • Em algum ponto, a chamada simplesmente não completa: timeout do lado do cliente, erro 504 do servidor, ou a ferramenta trava sem mensagem clara.
  • Rodar de novo não ajuda — o problema não é instabilidade pontual, é o tamanho da base combinado com o tipo de paginação.

Se esse padrão soa familiar — “funcionava bem quando a base era menor” — a causa provável é paginação por offset numa API que não oferece alternativa.

Por que isso importa além da exportação manual

O caso mais visível é a exportação pontual de relatório, mas o mesmo mecanismo afeta qualquer processo automatizado que precise varrer uma base inteira:

  • Sincronização entre sistemas. Um job noturno que copia todos os contatos do CRM para o data warehouse via API fica mais lento a cada mês que a base cresce, até estourar a janela de tempo disponível.
  • Pipelines de ETL. Se a ingestão de dados depende de paginar uma API de origem, o tempo de processamento cresce de forma não linear conforme a base de origem cresce — um problema silencioso que só aparece meses depois de o pipeline entrar em produção.
  • Auditorias e migrações. Trocar de CRM ou consolidar bases geralmente exige extrair tudo via API. Se a origem só oferece offset, a migração de uma base grande pode ser tecnicamente inviável dentro do prazo, e ninguém percebe isso até tentar.

O que fazer quando a API só oferece offset

Nem toda API vai adotar cursor amanhã, e trocar de fornecedor por causa disso raramente compensa. As saídas práticas, em ordem de preferência:

  • Verificar se existe endpoint alternativo. Muitos fornecedores mantêm o endpoint padrão em offset por compatibilidade, mas expõem uma versão mais nova com cursor para volumes grandes — geralmente documentada separadamente ou disponível sob pedido.
  • Exportar por faixa de data ou de ID. Em vez de pedir “página 5.000”, peça “todos os registros criados entre 1º e 15 de março”. Isso divide a base em fatias menores e evita que qualquer fatia individual fique grande o suficiente para travar — não elimina o problema de fundo, mas contorna na prática.
  • Reduzir o tamanho da página. Pedir páginas de 20 em vez de 100 registros não resolve a degradação, mas adia o ponto em que ela se torna crítica — é paliativo, não solução.
  • Pedir ao fornecedor. Se a exportação é uma necessidade recorrente e crítica, vale reportar o problema formalmente. Fornecedores de porte costumam ter roadmap para migrar de offset para cursor exatamente por essa queixa ser comum.

Um caso intermediário: paginação por timestamp

Existe uma terceira variante, menos discutida, que vale conhecer porque aparece com frequência em APIs de martech mais simples: paginação baseada em data de criação ou modificação, sem um cursor opaco formal. A chamada pede algo como “todos os registros criados depois de 2026-03-01T14:00:00”, e o servidor devolve o próximo lote a partir dali. Tecnicamente, isso se comporta como cursor — o servidor não precisa varrer e descartar nada anterior, desde que o campo de data tenha um índice adequado no banco — mas é mais simples de implementar do que um cursor opaco formal, porque usa um valor legível e previsível em vez de um token gerado especificamente para esse fim.

A armadilha dessa variante aparece quando múltiplos registros compartilham exatamente o mesmo timestamp — situação comum em importações em lote ou em bancos com baixa precisão de data. Nesse caso, a paginação por timestamp puro pode pular ou duplicar registros na fronteira entre duas páginas. APIs bem desenhadas resolvem isso combinando o timestamp com um segundo critério de desempate, geralmente o ID do registro, para garantir uma ordenação total e sem ambiguidade.

Reconhecendo cursor na documentação

Ao avaliar uma API antes de contratar uma ferramenta, alguns sinais na documentação indicam qual abordagem ela usa:

  • Parâmetros como page, offset ou skip combinados com limit ou size — sinal de offset.
  • Parâmetros como cursor, after, next_token ou um campo has_more com um token opaco na resposta — sinal de cursor.
  • APIs GraphQL modernas costumam seguir a especificação de conexões cursor-based formalizada pelo Facebook em 2015, reconhecível pelos campos edges, node e pageInfo — um padrão de mercado consolidado especificamente para resolver esse problema de escala.

Perguntar diretamente também funciona: “Ao paginar resultados grandes, a página 1.000 tem o mesmo tempo de resposta da página 1, ou fica mais lenta?” é uma pergunta que qualquer engenheiro de fornecedor consegue responder na hora, e a resposta revela imediatamente qual abordagem está por trás.

Por que o fornecedor não migra simplesmente

Vale entender que cursor não é estritamente melhor em todo cenário — é uma troca. Paginação por offset permite pular direto para qualquer página arbitrária (“me dê a página 50”), o que é útil em interfaces com numeração de página visível ao usuário. Cursor só permite avançar sequencialmente a partir de onde você parou — não dá para pular direto para “o meio” sem ter processado o que veio antes.

Isso explica por que interfaces com paginação numerada visível (1, 2, 3… 50) geralmente usam offset internamente, enquanto feeds de rolagem contínua (redes sociais, timelines) usam cursor. Para exportação de dados em massa — o caso que mais dói em martech — cursor quase sempre é a escolha certa, porque ninguém precisa “pular para a página 4.000” de uma exportação, só percorrer tudo uma vez.

Paginação e a decisão de arquitetura por trás dela

Vale situar essa escolha dentro de um quadro mais amplo: paginação por offset ou cursor é uma manifestação prática do mesmo raciocínio por trás de qualquer trade-off de arquitetura — simplicidade de implementação de um lado, desempenho em escala do outro. Cursor é mais trabalhoso de implementar corretamente (exige um campo ordenado e estável para servir de marcador, geralmente um ID crescente ou timestamp com precisão suficiente para não gerar ambiguidade entre registros criados quase ao mesmo tempo), enquanto offset é trivial de implementar sobre qualquer tabela, sem exigir esse cuidado extra de design.

Isso explica por que tantas APIs, especialmente as mais antigas ou as construídas rapidamente no início de um produto, escolhem offset por padrão — é o caminho de menor esforço de implementação — e só migram para cursor depois que o volume de dado real expõe a limitação. Para quem está especificando os requisitos de uma API nova, interna ou de um fornecedor, pedir cursor desde o início evita essa migração dolorosa mais tarde.

O efeito colateral menos óbvio: dado duplicado ou perdido durante a exportação

Existe uma armadilha adicional em paginação por offset que vai além da lentidão: se registros forem inseridos ou removidos durante o processo de exportação — algo comum quando a exportação de uma base grande leva minutos ou horas —, a numeração das páginas por offset pode “deslizar”. Um registro pode aparecer duas vezes em páginas diferentes, ou ser pulado inteiramente, porque a posição relativa de cada linha mudou entre uma chamada de página e a seguinte.

Paginação por cursor não sofre desse problema da mesma forma, porque o marcador aponta para uma posição fixa e específica (geralmente um ID), não para uma posição relativa que pode mudar conforme a base é alterada por outras operações em paralelo. Isso é especialmente relevante para exportações que rodam em produção, com o sistema recebendo escrita normal simultaneamente — cenário em que offset não garante apenas lentidão, mas também um resultado potencialmente incorreto.

Próximos passos para diagnosticar sua exportação

A ação concreta: da próxima vez que uma exportação ou sincronização travar em volume alto, olhe a URL ou os parâmetros da chamada de API por trás dela. Se você ver page= ou offset= combinado com uma base grande, agora você sabe o motivo exato — não é “muito dado”, é o tipo de paginação encontrando seu limite estrutural.

Se a exportação é recorrente e crítica para a operação, vale mapear hoje quais das suas integrações usam offset em bases que só crescem, antes que o timeout apareça durante uma migração ou auditoria com prazo apertado.

Compartilhe:
Foto de Começando na Web

Começando na Web

Dionatha é bacharel em Sistemas de Informação e especialista em Martech, com mais de 17 anos de experiência na integração de Marketing e Tecnologia para impulsionar negócios, equipes e profissionais a compreenderem e otimizarem as operações de marketing digital e tecnologia. Sua expertise técnica abrange áreas-chave como SEO técnico, Analytics, CRM, Chatbots, CRO (Conversion Rate Optimization) e automação de processos.

Sumário

Receba o melhor conteúdo sobre Marketing e Tecnologia

comunidade gratuita

Cadastre-se para o participar da primeira comunidade sobre Martech do brasil!