{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/power-automate-paginacao-throttling-apis-rest-alto-volume/","result":{"data":{"markdownRemark":{"frontmatter":{"title":"Power Automate: paginação e throttling em APIs REST de alto volume","description":"Como consumir APIs REST paginadas no Power Automate sem perder registros nem bater no throttle: pagination nativa, cursores, retry-after e controle de concorrência.","date":"19 de setembro de 2026","thumbnail":null},"html":"<p>Consumir uma API REST no Power Automate parece trivial até o dia em que o endpoint devolve mais de uma página de dados e o fluxo passa a processar só os primeiros 100 registros — silenciosamente. Ou até o momento em que a API começa a responder <code>429 Too Many Requests</code> sob carga e o fluxo falha de forma intermitente, sem padrão claro. Esses dois problemas — <strong>paginação</strong> e <strong>throttling</strong> — são a diferença entre uma integração de demonstração e uma integração que sobrevive em produção com volume real.</p>\n<p><strong>Paginação: por que o resultado \"completo\" quase nunca é completo</strong></p>\n<p>Quase toda API REST corporativa limita o tamanho da resposta. Ela devolve um bloco de registros e uma pista de como buscar o próximo. As três estratégias mais comuns são:</p>\n<ol>\n<li><strong>Offset/limit</strong> — você envia <code>?offset=200&#x26;limit=100</code> e incrementa o offset a cada chamada até vir uma página vazia. Simples, mas frágil se registros forem inseridos entre as chamadas (pode duplicar ou pular linhas).</li>\n<li><strong>Cursor/continuation token</strong> — a resposta traz um token opaco (<code>nextPageToken</code>, <code>@odata.nextLink</code>, <code>continuation</code>) que você passa na próxima requisição. É o padrão mais robusto porque a API garante consistência da sequência.</li>\n<li><strong>Link header (RFC 5988)</strong> — o próximo endereço vem no header <code>Link</code> com <code>rel=\"next\"</code>. Comum em APIs REST públicas (GitHub, por exemplo).</li>\n</ol>\n<p>O conector HTTP do Power Automate <strong>não pagina sozinho</strong>. Se você usa a ação HTTP genérica, precisa implementar o laço manualmente: uma variável para o cursor/offset, um <code>Do until</code> que roda enquanto houver próxima página, e dentro dele a chamada HTTP seguida da extração do token da resposta. O erro clássico é montar a condição de parada olhando só a contagem de itens — o certo é parar quando o campo de continuação vier nulo ou vazio, não quando a página vier \"pequena\".</p>\n<p>Já os <strong>custom connectors</strong> têm suporte nativo a paginação: no editor, você define o campo que contém o próximo link e o Power Automate itera automaticamente, devolvendo a coleção agregada. É a forma mais limpa quando a API segue um padrão previsível de <code>nextLink</code>.</p>\n<p><strong>Throttling: o 429 não é um erro, é uma instrução</strong></p>\n<p>Quando uma API responde <code>429</code>, ela não está quebrada — está pedindo para você desacelerar. O comportamento profissional é respeitar o header <code>Retry-After</code> (em segundos ou como data HTTP) que quase sempre acompanha a resposta. Ignorar isso e simplesmente tentar de novo imediatamente só piora o quadro e pode levar a bloqueio temporário do cliente.</p>\n<p>O Power Automate tem uma <strong>retry policy</strong> por ação (Settings → Retry Policy), com modos:</p>\n<ul>\n<li><strong>Exponential</strong> — espera crescente entre tentativas (recomendado como padrão para 429/500).</li>\n<li><strong>Fixed interval</strong> — intervalo constante.</li>\n<li><strong>None</strong> — desliga o retry (útil quando você quer tratar o erro manualmente).</li>\n</ul>\n<p>A retry policy nativa cobre <code>408</code>, <code>429</code> e <code>5xx</code> automaticamente e, importante, <strong>honra o <code>Retry-After</code> quando presente</strong>. Para a maioria dos casos, configurar exponential com um número razoável de tentativas já resolve. Quando a lógica de espera precisa ser mais fina — por exemplo, ler o <code>Retry-After</code> da resposta e usá-lo num <code>Delay</code> dinâmico dentro de um <code>Scope</code> com padrão Try/Catch — aí você desliga a retry nativa (<code>None</code>) e assume o controle.</p>\n<p><strong>Controle de concorrência: o gargalo que você mesmo cria</strong></p>\n<p>Um erro sutil é combinar paginação com <code>Apply to each</code> em modo paralelo alto. Se você processa cada página abrindo 50 chamadas simultâneas para a mesma API, você fabrica o próprio <code>429</code>. Ajuste o <strong>Concurrency Control</strong> do <code>Apply to each</code> para um grau compatível com o rate limit documentado da API — muitas APIs corporativas toleram bem 5 a 10 requisições concorrentes, mas não 50. Menos concorrência com retry saudável quase sempre termina mais rápido do que muita concorrência batendo em throttle.</p>\n<p><strong>Padrão de referência para produção</strong></p>\n<p>Para uma integração de alto volume que precisa ser confiável, o desenho que recomendamos combina:</p>\n<ul>\n<li>Um <code>Do until</code> (ou custom connector com paginação nativa) para varrer todas as páginas usando cursor, nunca offset quando houver alternativa.</li>\n<li>Retry policy exponential nas ações HTTP, respeitando <code>Retry-After</code>.</li>\n<li>Um <code>Scope</code> Try/Catch envolvendo o bloco crítico, com <code>result()</code> para identificar exatamente qual chamada falhou.</li>\n<li>Concorrência limitada e conservadora no processamento dos itens.</li>\n<li>Persistência incremental (gravar cada página no Dataverse/SharePoint antes de buscar a próxima), para que uma falha na página 40 não obrigue a reprocessar as 39 anteriores — o que, combinado com <strong>alternate keys e upsert no Dataverse</strong>, torna o reprocessamento idempotente.</li>\n</ul>\n<p><strong>Quando a integração cresce demais para o fluxo</strong></p>\n<p>Se o volume passa de dezenas de milhares de registros por execução, se a janela de tempo aperta ou se o custo de ações consumidas dispara, esse é o sinal de que a carga deveria migrar para uma <strong>Azure Function</strong> ou <strong>Logic App</strong>, deixando o Power Automate como orquestrador e não como motor de laço. O laço de paginação em código roda mais rápido, mais barato e com controle total de backoff.</p>\n<p>Integrações que puxam dados de sistemas externos em escala são exatamente o tipo de projeto onde detalhes de paginação e throttling separam o piloto que \"funcionou na demo\" do serviço que roda todo dia sem intervenção. Se sua empresa depende dessas integrações, contar com um parceiro que já enfrentou esses limites em produção — como a Dynamic Soluções, via consultoria ou pela plataforma self-service de Power Platform — encurta bastante o caminho até uma arquitetura resiliente.</p>\n<p>Consuming a REST API in Power Automate looks trivial until the day the endpoint returns more than one page of data and the flow starts processing only the first 100 records — silently. Or the moment the API begins responding with <code>429 Too Many Requests</code> under load and the flow fails intermittently, with no clear pattern. These two problems — <strong>pagination</strong> and <strong>throttling</strong> — are the difference between a demo integration and one that survives in production with real volume.</p>\n<p><strong>Pagination: why the \"complete\" result is almost never complete</strong></p>\n<p>Nearly every corporate REST API limits the size of its response. It returns a block of records plus a hint on how to fetch the next one. The three most common strategies are:</p>\n<ol>\n<li><strong>Offset/limit</strong> — you send <code>?offset=200&#x26;limit=100</code> and increment the offset on each call until an empty page comes back. Simple, but fragile if records are inserted between calls (it can duplicate or skip rows).</li>\n<li><strong>Cursor/continuation token</strong> — the response carries an opaque token (<code>nextPageToken</code>, <code>@odata.nextLink</code>, <code>continuation</code>) that you pass into the next request. This is the most robust pattern because the API guarantees sequence consistency.</li>\n<li><strong>Link header (RFC 5988)</strong> — the next address comes in the <code>Link</code> header with <code>rel=\"next\"</code>. Common in public REST APIs (GitHub, for example).</li>\n</ol>\n<p>Power Automate's HTTP connector <strong>does not paginate on its own</strong>. If you use the generic HTTP action, you must implement the loop manually: a variable for the cursor/offset, a <code>Do until</code> that runs while there is a next page, and inside it the HTTP call followed by extracting the token from the response. The classic mistake is building the stop condition based solely on item count — the right thing is to stop when the continuation field comes back null or empty, not when a page comes back \"small.\"</p>\n<p><strong>Custom connectors</strong>, on the other hand, have native pagination support: in the editor you define the field containing the next link and Power Automate iterates automatically, returning the aggregated collection. This is the cleanest approach when the API follows a predictable <code>nextLink</code> pattern.</p>\n<p><strong>Throttling: the 429 isn't an error, it's an instruction</strong></p>\n<p>When an API responds with <code>429</code>, it isn't broken — it's asking you to slow down. The professional behavior is to respect the <code>Retry-After</code> header (in seconds or as an HTTP date) that almost always accompanies the response. Ignoring it and simply retrying immediately only makes things worse and can lead to a temporary client block.</p>\n<p>Power Automate has a per-action <strong>retry policy</strong> (Settings → Retry Policy), with modes:</p>\n<ul>\n<li><strong>Exponential</strong> — growing wait between attempts (recommended as the default for 429/500).</li>\n<li><strong>Fixed interval</strong> — constant interval.</li>\n<li><strong>None</strong> — turns retry off (useful when you want to handle the error manually).</li>\n</ul>\n<p>The native retry policy automatically covers <code>408</code>, <code>429</code>, and <code>5xx</code> and, importantly, <strong>honors <code>Retry-After</code> when present</strong>. For most cases, configuring exponential with a reasonable number of attempts already solves it. When the wait logic needs to be finer — for example, reading <code>Retry-After</code> from the response and using it in a dynamic <code>Delay</code> inside a <code>Scope</code> with a Try/Catch pattern — you turn native retry off (<code>None</code>) and take control.</p>\n<p><strong>Concurrency control: the bottleneck you create yourself</strong></p>\n<p>A subtle mistake is combining pagination with <code>Apply to each</code> in high parallel mode. If you process each page by firing 50 simultaneous calls to the same API, you manufacture your own <code>429</code>. Adjust the <strong>Concurrency Control</strong> of the <code>Apply to each</code> to a degree compatible with the API's documented rate limit — many corporate APIs tolerate 5 to 10 concurrent requests well, but not 50. Less concurrency with healthy retry almost always finishes faster than heavy concurrency hitting throttle.</p>\n<p><strong>A reference pattern for production</strong></p>\n<p>For a high-volume integration that needs to be reliable, the design we recommend combines:</p>\n<ul>\n<li>A <code>Do until</code> (or a custom connector with native pagination) to sweep all pages using a cursor, never offset when there's an alternative.</li>\n<li>Exponential retry policy on HTTP actions, respecting <code>Retry-After</code>.</li>\n<li>A <code>Scope</code> Try/Catch wrapping the critical block, with <code>result()</code> to identify exactly which call failed.</li>\n<li>Limited, conservative concurrency when processing items.</li>\n<li>Incremental persistence (writing each page to Dataverse/SharePoint before fetching the next), so that a failure on page 40 doesn't force reprocessing the previous 39 — which, combined with <strong>alternate keys and upsert in Dataverse</strong>, makes reprocessing idempotent.</li>\n</ul>\n<p><strong>When the integration grows too big for the flow</strong></p>\n<p>If volume exceeds tens of thousands of records per run, if the time window tightens, or if the cost of consumed actions spikes, that's the signal that the workload should move to an <strong>Azure Function</strong> or <strong>Logic App</strong>, leaving Power Automate as the orchestrator rather than the loop engine. A pagination loop in code runs faster, cheaper, and with full backoff control.</p>\n<p>Integrations that pull data from external systems at scale are exactly the kind of project where pagination and throttling details separate the pilot that \"worked in the demo\" from the service that runs every day without intervention. If your company depends on these integrations, working with a partner that has already faced these limits in production — such as Dynamic Soluções, through consulting or the Power Platform self-service platform — shortens the path to a resilient architecture considerably.</p>"}},"pageContext":{"slug":"/blog/power-automate-paginacao-throttling-apis-rest-alto-volume/","previousPost":null,"nextPost":{"frontmatter":{"title":"Dataverse: alternate keys e upsert para integracoes idempotentes"},"fields":{"slug":"/blog/dataverse-alternate-keys-upsert-integracao/"}}}},"staticQueryHashes":["2269431855"]}