Selo de estado:
Preview(teto atual do produto) · Curso ACD-250 — Integrações e consumo externo · Aula 5 de 6 · Atualizado em 2026-10-04.
Objetivo#
Ao final desta aula você vai diagnosticar 429 com Retry-After — e distinguir, pelo código HTTP, o que é seu erro, o que é teto de requisição, o que é dinheiro e o que é indisponibilidade proposital.
Vídeo#
Identificador no manifesto: acd-250-05-erros-rate-limit-idempotencia · duração-alvo 6 min · tela do produto: /connect.
Roteiro de gravação (5 capítulos):
| # | Minutagem-alvo | Capítulo | Tela do produto |
|---|---|---|---|
| 1 | 0:00–0:30 | Abertura: título + selo. Um formato de erro para tudo: { "error": "mensagem em português" }. | /connect |
| 2 | 0:30–2:15 | O catálogo de códigos lido em voz alta, em quatro famílias: você · credencial · dinheiro · plataforma. | /connect |
| 3 | 2:15–3:45 | Rate limit: 120/min por chave, 240/min por workspace; 429 com Retry-After. E o 503 fail-closed do limitador. | /connect |
| 4 | 3:45–5:00 | Paginação (1.000 por página, 1.000.000 de profundidade) e idempotência: a API é somente leitura, logo repetir não muda nada. | /excel |
| 5 | 5:00–6:00 | Webhooks são Roadmap: como reagir a mudanças hoje. Erros comuns e encerramento. | /connect |
Conteúdo#
Esta é a aula dos contratos transversais — o que vale para todas as rotas /api/v1/**, independentemente da superfície. É aula de conhecimento porque não há nada para configurar: o que existe aqui é a capacidade de ler uma resposta de erro e saber o que fazer.
Começa com uma boa notícia: há um formato de erro para tudo.
{ "error": "Mensagem explicando o que aconteceu." }Sempre JSON, sempre com mensagem em português, sempre com o código HTTP correspondente. As respostas — de sucesso e de erro — carregam X-Ingestia-Access-Scope: workspace, lembrete de que a credencial lê o workspace inteiro; o OData acrescenta OData-Version: 4.0.
O catálogo, em quatro famílias
| Código | Significado | Família | Causas típicas |
|---|---|---|---|
200 · 204 | OK · sem conteúdo | — | leitura bem-sucedida · pré-flight OPTIONS (CORS) |
400 | requisição inválida | você | JSON malformado, sql ausente, $skiptoken inválido, paginação além do teto |
401 | não autenticado | credencial | chave ausente, inválida ou revogada |
403 | proibido | credencial | papel ou escopo insuficiente, SQL não-SELECT, referência fora do workspace ou fora dos marts |
404 | não encontrado | você | EntitySet OData inexistente (também protege contra enumeração) |
402 | pagamento necessário | dinheiro | workspace inadimplente ou suspenso — extração paga bloqueada |
429 | muitas requisições | teto | estourou o rate limit — traz Retry-After |
501 | não implementado | você | operação OData fora do subset suportado |
502 | erro no datalake | plataforma | falha ao executar a consulta no BigQuery |
503 | indisponível | plataforma | datalake não provisionado, nuvem própria caída, ou limitador indisponível — traz Retry-After |
Ler por família acelera o diagnóstico: 400/404/501 você corrige na sua requisição; 401/403 você corrige na credencial (Aula 2); 402 é a regra do dinheiro; 429/503 você espera, não insiste.
Rate limit: 120/min, e o 503 que protege o seu bolso
Os limites são por janela de 1 minuto, aplicados por chave e por workspace — assim uma chave vazada não fura o teto do workspace:
| Bucket | Por chave | Por workspace |
|---|---|---|
Leitura (OData, tables) | 120/min | 240/min |
SQL livre (query) | 60/min | 120/min |
Estourou? 429 com Retry-After: 60. O comportamento correto do cliente é simples e quase sempre feito errado: leia o Retry-After e espere o que ele diz, em vez de tentar de novo imediatamente. Reduzir paralelismo resolve mais do que repetir.
Agora a parte contraintuitiva e a mais importante desta aula. Se o serviço de rate limit ficar indisponível, a API nega com 503 em vez de liberar sem teto. Chama-se fail-closed, e a razão é econômica: as rotas /api/v1 executam BigQuery pago. Liberar sem limitador seria arriscar fatura ilimitada em nome da disponibilidade. O produto escolhe recusar.
Aviso
429 e 503 não são a mesma coisa
429 diz "você passou do seu teto" — é seu, e você controla reduzindo o ritmo. 503 com Retry-After diz "a plataforma não pode garantir o teto agora" — não é seu, e insistir não melhora. Ambos pedem a mesma reação imediata: respeitar o Retry-After.
Um detalhe que tranquiliza: os buckets da API são separados do BI nativo. Consumo externo pesado via Power BI não degrada o BI dentro do produto.
Paginação
Duas formas, porque são duas superfícies:
- OData (
Preview, Aula 3): server-driven, páginas de até 1.000 linhas com@odata.nextLink; siga o link exatamente (ele carrega um$skiptokenopaco — token adulterado responde400).Prefer: odata.maxpagesize=Nreduz a página (teto 1.000) e a resposta confirma comPreference-Applied. Profundidade máxima: 1.000.000 de linhas por consulta; acima,400orientando a filtrar. - REST (
/api/v1/tables/{dataset}/{table}, fora de GA, Aula 6):limit(padrão 100, máximo 1000) eoffset, comnextOffsetna resposta —nullno fim.
E a regra de custo que vale para as duas: LIMIT, OFFSET e paginação não reduzem bytes lidos no BigQuery. Para pagar menos, filtre e agregue.
Idempotência: a resposta curta é "a API é somente leitura"
Não existe endpoint de escrita no ingestia.io. Toda rota é GET — ou POST apenas para enviar um SELECT. Logo, as chamadas são idempotentes por natureza: repetir não altera estado. Não há cabeçalho Idempotency-Key, e não é esquecimento: sem escrita, ele não tem o que proteger. Um mecanismo de idempotência só faria sentido junto de uma futura API de escrita, que é Roadmap.
Como bônus, consultas idênticas (mesma versão do workspace) servem do cache com custo R$ 0, e a invalidação por pipeline garante que nunca se serve dado velho.
Webhooks: não existem hoje
Não há API pública de assinatura de webhooks — eventos do workspace enviados ao seu endpoint. Está no Roadmap. Para reagir a mudanças de dados hoje, há dois caminhos legítimos: consulta periódica do feed OData (a atualização incremental do Power BI é exatamente isso) ou as assinaturas e alertas do próprio produto, conforme o plano. Os endpoints de webhook que existem na plataforma são entradas internas de cobrança e marketing, não uma API para desenvolvedores.
Exemplo: a Aurora Varejo às 6h
O servidor de integração da Aurora dispara 40 atualizações de Power BI em paralelo às 6h. Na terceira, começam a chover 429 com Retry-After: 60. O time lê o cabeçalho e descobre o óbvio: 40 refreshes paralelos, cada um paginando várias páginas, passam fácil de 120 chamadas no minuto com a mesma chave. A correção tem duas partes: escalonar os refreshes ao longo de 15 minutos e filtrar por janela de data para que cada um faça menos páginas. Semanas depois aparece um 503 com Retry-After num horário aleatório — o limitador estava indisponível, e a API negou de propósito para não rodar consulta cobrável sem teto. A resposta certa foi esperar, não repetir em laço.
| Superfície | Estado | Quando usar |
|---|---|---|
| Contratos transversais (formato de erro, paginação, rate limit fail-closed) | Preview | valem para toda rota /api/v1 — é o que esta aula ensina a ler |
| Rate limit de leitura 120/min por chave | Preview | dimensione o seu cliente por ele; respeite o Retry-After |
Cabeçalho Idempotency-Key | não existe | desnecessário: a API é somente leitura |
| Assinatura de webhooks · API de escrita | Roadmap | não construa — use consulta periódica do OData ou alertas do produto |
Erros comuns
| Sintoma | Causa provável | O que fazer |
|---|---|---|
429 em rajada | muitas chamadas na mesma janela de 1 min | respeite o Retry-After; reduza paralelismo e escalone horários |
Laço de repetição imediata depois de 429 | cliente ignorando o Retry-After | espere o tempo indicado — repetir só prolonga o bloqueio |
503 com Retry-After interpretado como bug | limitador indisponível → negar é o desenho | aguarde e repita; confirme o provisionamento do datalake |
402 | workspace inadimplente ou suspenso | regularize o pagamento no app |
400 na paginação | passou de 1.000.000 de linhas, ou $skiptoken adulterado | filtre os dados; siga o @odata.nextLink |
Esperar Idempotency-Key ou webhook | ambos não existem (escrita e webhooks são Roadmap) | a API é somente leitura; reaja por consulta periódica |
| Esperar SLA de disponibilidade da API | Preview é sem SLA; uptime e latência não são medidos | não prometa número a terceiro |
Estado
Os contratos desta aula — formato de erro único, catálogo de códigos, paginação e rate limit fail-closed — são Preview e cobertos por teste automatizado. O que não existe: SLA, número de uptime, latência ou throughput como garantia; RPO/RTO como promessa; Idempotency-Key; API de escrita; assinatura de webhooks (Roadmap). O valor em x-ingestia-cost-brl é projeção. E lembre do estado das superfícies: OData = Preview, API REST de consulta = fora de GA (Aula 6).
Faça você mesmo#
Esta aula é de conhecimento: não há exercício operacional. Leia, assista e responda à checagem rápida.
Para fixar sem operar nada, faça o exercício de mesa: pegue os sete códigos da tabela de erros comuns e, para cada um, escreva numa linha de quem é o problema (seu, da credencial, do dinheiro ou da plataforma) e qual é a primeira ação. Depois dimensione no papel quantas chamadas por minuto a sua integração faria no pior horário, e compare com 120/min por chave. Em nenhum momento tente provocar 429 de propósito contra a rota /api/v1/query — ela está fora de GA e não deve receber tráfego seu (Aula 6).
Checagem rápida#
Três perguntas no final da aula, corrigidas no servidor. A aula só conta como concluída depois da checagem.
Documentação relacionada#
Capacidades ensinadas#
(conceitual — sem capacidade específica da matriz) — o selo exibido na aula é sempre o estado mais conservador entre as capacidades citadas; nada aqui é "GA".