Seu relatório de contas a receber puxa todo o histórico da Conta Azul numa chamada só, de 2019 até hoje? Funciona. Ou funcionava, até cair em timeout num dia aleatório e você ter que clicar em "Atualizar" de novo, rsrsrs.

A Conta Azul avisou os integradores: a partir de 10/11/2026, as buscas de contas a pagar e a receber passam a ter dois limites. Período máximo de 1 ano em todos os filtros de data e tamanho_pagina só com os valores da documentação. Fora disso, a API devolve erro 400, e a sua atualização para.

Neste passo a passo você vai ajustar a carga no Power BI (Power Query M) e em Python para buscar em janelas de 1 ano, paginar do jeito certo e, de quebra, montar uma sincronização incremental que pesa muito menos. Bora lá.

Requisitos

  • API Conta Azul, módulo Financeiro v1, servidor https://api-v2.contaazul.com
  • Aplicação cadastrada no Portal do Desenvolvedor da Conta Azul e um token de acesso válido (OAuth 2.0). Se ainda não tem, comece pelo artigo Conta Azul: como tratar o Extrato de Movimentações no Power BI
  • Power BI Desktop (Power Query) ou Python 3 com a biblioteca requests
  • Válido em: outubro/2026, conforme o comunicado da Conta Azul aos integradores, a especificação OpenAPI do Financeiro e o changelog oficial

O que muda em 10/11/2026

Os limites valem para quatro rotas:

GET /v1/financeiro/eventos-financeiros/contas-a-pagar/buscar
GET /v1/financeiro/eventos-financeiros/contas-a-receber/buscar
GET /v1/financeiro/contas-a-pagar
GET /v1/financeiro/contas-a-receber

As duas últimas são as rotas novas da mesma busca e seguem as mesmas regras.

ParâmetroHojeA partir de 10/11/2026
data_vencimento_de / _ateSem limiteAté 1 ano
data_competencia_de / _ateSem limiteAté 1 ano
data_pagamento_de / _ateSem limiteAté 1 ano
data_criacao_de / _ateSem limiteAté 1 ano
data_alteracao_de / _ateAté 1 anoSem mudança
tamanho_paginaQualquer valor10, 20, 50, 100, 200, 500 ou 1000

O filtro de vencimento (data_vencimento_de e data_vencimento_ate) continua obrigatório. O motivo, segundo a própria Conta Azul: buscas de vários anos com centenas de páginas pesam no banco, deixam a API lenta para todo mundo e muitas vezes terminam em timeout (erro 500). Com o limite, a resposta fica previsível. Se passar do limite, o erro 400 vem na hora, com uma mensagem dizendo o que ajustar.

Atenção

a busca por POST nesses mesmos caminhos já deixou de existir em 19/10/2026. Se a sua integração ainda faz POST .../buscar, troque para GET, com os filtros na query string.

1 Quebre o período em janelas de 1 ano

A regra prática é a do próprio exemplo da Conta Azul: uma chamada por ano-calendário, de 01/01 a 31/12. Para buscar de 2024 a 2026:

?data_vencimento_de=2024-01-01&data_vencimento_ate=2024-12-31
?data_vencimento_de=2025-01-01&data_vencimento_ate=2025-12-31
?data_vencimento_de=2026-01-01&data_vencimento_ate=2026-12-31

Por que ano-calendário e não "hoje menos 365 dias"? Porque as janelas ficam fixas, fáceis de conferir e sem sobreposição. E 2024, que é bissexto, está no exemplo oficial.

Dica

conta a pagar e a receber tem vencimento no futuro. Não pare a carga em "hoje". Vá até o fim do ano que vem (ou até o horizonte que o seu fluxo de caixa usa), senão as parcelas futuras somem do relatório.

2 Use um tamanho de página válido e percorra as páginas

tamanho_pagina passa a aceitar só 10, 20, 50, 100, 200, 500 ou 1000. Se você usa outro valor (300, 5000...), troque pelo permitido mais próximo, até 1000. Para carga de BI, use 1000: menos chamadas por janela.

A resposta traz itens_totais, itens e totais. Com itens_totais você sabe quantas páginas existem e para de chamar na hora certa:

páginas = arredonda_para_cima(itens_totais / tamanho_pagina)
Atenção

a documentação marca tamanho_pagina como obrigatório, e o comunicado diz que, sem ele, o padrão é 10. Envie sempre. Página de 10 itens multiplica as chamadas por 100.

3 No Power BI: consulta M com janelas e paginação

Abra o Power Query (Página Inicial > Transformar dados), crie uma Consulta Nula (Nova Fonte > Consulta Nula), abra o Editor Avançado e cole:

let
    // Ajuste o período e o token (veja o artigo de token da Conta Azul)
    Token = "SEU_TOKEN",
    Inicio = #date(2024, 1, 1),
    Fim = #date(Date.Year(DateTime.Date(DateTime.LocalNow())) + 1, 12, 31),
    TamanhoPagina = 1000,

    // 1. Uma janela por ano-calendário (máximo de 1 ano por busca)
    Janelas = List.Transform(
        {Date.Year(Inicio) .. Date.Year(Fim)},
        each [
            de  = Date.ToText(List.Max({#date(_, 1, 1), Inicio}), "yyyy-MM-dd"),
            ate = Date.ToText(List.Min({#date(_, 12, 31), Fim}), "yyyy-MM-dd")
        ]
    ),

    // 2. Busca uma página de uma janela
    BuscarPagina = (janela as record, pagina as number) as record =>
        Json.Document(
            Web.Contents(
                "https://api-v2.contaazul.com",
                [
                    RelativePath = "v1/financeiro/eventos-financeiros/contas-a-receber/buscar",
                    Query = [
                        pagina = Text.From(pagina),
                        tamanho_pagina = Text.From(TamanhoPagina),
                        data_vencimento_de = janela[de],
                        data_vencimento_ate = janela[ate]
                    ],
                    Headers = [Authorization = "Bearer " & Token]
                ]
            )
        ),

    // 3. Todas as páginas de uma janela, usando itens_totais
    BuscarJanela = (janela as record) as list =>
        let
            Primeira = BuscarPagina(janela, 1),
            TotalPaginas = Number.RoundUp(Primeira[itens_totais] / TamanhoPagina),
            Demais = List.Transform({2 .. TotalPaginas}, each BuscarPagina(janela, _)[itens])
        in
            List.Combine({Primeira[itens]} & Demais),

    // 4. Junta todas as janelas numa tabela
    Itens = List.Combine(List.Transform(Janelas, BuscarJanela)),
    Tabela = Table.FromRecords(Itens, null, MissingField.UseNull)
in
    Tabela

Conforme a especificação oficial da API; não executado aqui, porque exige o token da sua conta.

O que vale entender:

  • URL base fixa + RelativePath + Query: é isso que permite a atualização agendada no serviço do Power BI. Se você montar a URL inteira concatenando texto, o serviço reclama de fonte dinâmica e não atualiza.
  • {2 .. TotalPaginas}: quando a janela tem uma página só (ou nenhuma), essa lista fica vazia, e a consulta não faz chamada extra.
  • Para contas a pagar, troque o RelativePath para v1/financeiro/eventos-financeiros/contas-a-pagar/buscar. O resto é igual.
  • Cada item vem com id, descricao, data_vencimento, status, total, pago, nao_pago, data_competencia, data_alteracao, categorias, centros_custo e cliente (ou fornecedor, em contas a pagar). Expanda as colunas que o seu relatório usa.
Atenção

o token não fica no código em produção. Use o fluxo de token que você já tem (parâmetro ou consulta que gera o token) e só referencie aqui.

4 Em Python: carga em janelas com paginação

Para quem carrega um banco próprio (ou usa Pentaho/n8n e quer a lógica pronta), este script faz o mesmo e respeita o limite de requisições:

import datetime as dt
import time

import requests

BASE = "https://api-v2.contaazul.com"
TOKEN = "SEU_TOKEN"
CAMINHO = "/v1/financeiro/eventos-financeiros/contas-a-receber/buscar"
TAMANHOS_VALIDOS = (10, 20, 50, 100, 200, 500, 1000)


def janelas_anuais(inicio, fim):
    """Quebra o período em anos-calendário: 01/01 a 31/12, cortando nas pontas."""
    for ano in range(inicio.year, fim.year + 1):
        yield max(dt.date(ano, 1, 1), inicio), min(dt.date(ano, 12, 31), fim)


def buscar_janela(sessao, de, ate, tamanho_pagina=1000, filtros_extras=None):
    """Percorre todas as páginas de uma janela de vencimento."""
    if tamanho_pagina not in TAMANHOS_VALIDOS:
        raise ValueError(f"tamanho_pagina precisa ser um de {TAMANHOS_VALIDOS}")
    pagina = 1
    while True:
        params = {
            "pagina": pagina,
            "tamanho_pagina": tamanho_pagina,
            "data_vencimento_de": de.isoformat(),
            "data_vencimento_ate": ate.isoformat(),
            **(filtros_extras or {}),
        }
        resp = sessao.get(BASE + CAMINHO, params=params, timeout=60)
        if resp.status_code == 429:  # passou do limite de requisições: espera e repete
            time.sleep(int(resp.headers.get("Retry-After", 5)))
            continue
        if resp.status_code == 400:  # a API diz o que ajustar no corpo do erro
            raise RuntimeError(f"400 na janela {de} a {ate}: {resp.text}")
        resp.raise_for_status()

        corpo = resp.json()
        itens = corpo.get("itens", [])
        yield from itens
        if not itens or pagina * tamanho_pagina >= corpo.get("itens_totais", 0):
            break
        pagina += 1
        time.sleep(0.15)  # ~6 chamadas/s, abaixo do limite de 10/s


def carregar(inicio, fim, filtros_extras=None):
    sessao = requests.Session()
    sessao.headers["Authorization"] = f"Bearer {TOKEN}"
    contas = []
    for de, ate in janelas_anuais(inicio, fim):
        contas.extend(buscar_janela(sessao, de, ate, filtros_extras=filtros_extras))
    return contas


if __name__ == "__main__":
    hoje = dt.date.today()
    contas = carregar(dt.date(2024, 1, 1), dt.date(hoje.year + 1, 12, 31))
    print(f"{len(contas)} contas a receber carregadas")

Este script foi executado contra o mock server oficial da documentação da Conta Azul. A resposta veio no formato documentado (itens_totais, itens, totais), e a paginação parou no lugar certo. Contra a API real, troque SEU_TOKEN pelo seu token.

Por que o time.sleep(0.15)? O limite da API é de 600 chamadas por minuto e até 10 por segundo por conta conectada. Passando disso, vem 429 Too Many Requests. Paginar 1000 em 1000 com uma pausa curta mantém você longe do limite.

5 Sincronize só o que mudou (carga incremental)

Depois da carga inicial, não baixe tudo de novo todo dia. Os filtros data_alteracao_de e data_alteracao_ate trazem criações, edições, baixas, estornos e cancelamentos. Como o vencimento continua obrigatório, combine a data de alteração com as mesmas janelas de 1 ano:

agora = dt.datetime.now()
ontem = agora - dt.timedelta(days=1)
hoje = dt.date.today()

mudancas = carregar(
    dt.date(2024, 1, 1),
    dt.date(hoje.year + 1, 12, 31),
    filtros_extras={
        "data_alteracao_de": ontem.strftime("%Y-%m-%dT%H:%M:%S"),
        "data_alteracao_ate": agora.strftime("%Y-%m-%dT%H:%M:%S"),
    },
)
# atualize no seu banco cada conta de `mudancas` pelo campo `id`

A documentação define a data de alteração em ISO 8601, no horário de São Paulo (GMT-3), e o exemplo oficial usa o formato 2025-10-20T07:00:00, sem fuso. É o formato do código acima. A janela de alteração também é limitada a 365 dias.

Este trecho segue a documentação; não foi executado contra a API real. O mock server da documentação é mais rígido que o exemplo oficial e só aceita a data com fuso (2025-10-20T07:00:00-03:00). Se a API real recusar o formato sem fuso, acrescente -03:00.

Atenção

conta excluída não aparece na busca por alteração. Ela simplesmente para de vir. Para não manter registro fantasma, faça de tempos em tempos (por exemplo, uma vez por dia) uma varredura completa em janelas de 1 ano e apague o que não voltou:

ids_api = {conta["id"] for conta in carregar(dt.date(2024, 1, 1), dt.date(hoje.year + 1, 12, 31))}
excluidos = ids_no_seu_banco - ids_api  # ids_no_seu_banco: conjunto de ids que você já tem

No Power BI em modo de importação, cada atualização recarrega a tabela inteira, então exclusão não é problema. A carga incremental e a varredura fazem diferença para quem guarda os dados num banco próprio.

Erros comuns

Erro 1

Erro 400 depois de 10/11/2026

A partir dessa data, período de busca maior que 1 ano ou tamanho_pagina fora da lista retornam 400. Os erros do Financeiro vêm no formato:

{"error": "<mensagem>"}

A Conta Azul ainda não publicou o texto exato dessa mensagem. Registre o corpo da resposta, como o script Python faz no RuntimeError, para saber qual parâmetro ajustar. Correção: confira se cada janela tem no máximo 1 ano e se tamanho_pagina é 10, 20, 50, 100, 200, 500 ou 1000.

Erro 2

Erro 500 ou timeout em busca longa

É exatamente o problema que motivou a mudança: períodos de vários anos com centenas de páginas. Correção: janelas de 1 ano, como no passo 1, já resolvem, mesmo antes de 10/11.

Erro 3

429 Too Many Requests

Você passou de 10 chamadas por segundo ou 600 por minuto. Correção: espere e repita (o script já faz isso) e mantenha uma pausa curta entre páginas.

Erro 4

Busca sem vencimento

data_vencimento_de e data_vencimento_ate são obrigatórios, inclusive na carga incremental por data de alteração. Correção: sempre envie as duas datas da janela.

Erro 5

POST em /buscar

A busca por POST deixou de existir em 19/10/2026. Correção: use GET no mesmo caminho, com os filtros como parâmetros da URL.

Bônus

Dica bônus

Se você só precisa das contas em aberto para o fluxo de caixa, filtre por status além das janelas. Menos itens por janela, menos páginas, atualização mais rápida. Confira na documentação os valores aceitos de status antes de fixar no código.

Conclusão

Com janelas de 1 ano, tamanho_pagina=1000 e paginação por itens_totais, a sua carga continua funcionando depois de 10/11/2026 e ainda fica mais estável do que hoje. Para quem mantém banco próprio, a sincronização por data de alteração com a varredura de exclusões deixa a rotina diária bem mais leve, para você e para a API.

Agora é só adaptar para o seu projeto: contas a pagar, contas a receber, e o horizonte de datas do seu negócio. Qualquer dúvida, comenta aqui.

E se você quer dominar esse tipo de integração do começo: na Formação Chora API, as aulas usam consultas reais nos sistemas Conta Azul, Omie, Bling e Nibo.

Quer dominar integrações com o Conta Azul e outros ERPs?

Na Formação Chora API você aprende a puxar os dados direto do sistema por API e a atualizar o relatório sozinho. As aulas usam consultas reais em Conta Azul, Omie, Bling e Nibo.

Ver a Formação →

Referências