Busca avançada no extrato
Busca avançada no extrato
O extrato comum (GET /v1/accounts/{accountId}/statement) filtra por período,
tipo de operação e ordem. Essas três coisas o liquidante sabe fazer, e por isso
elas são baratas.
Perguntas como “quais recebimentos caíram nesta chave PIX”, “o que veio
deste CNPJ” ou “quais lançamentos passaram de R$ 5.000” o liquidante não
sabe responder. A GET /v1/accounts/{accountId}/statement/advanced responde —
percorrendo o extrato do período e avaliando linha a linha.
Cada chamada varre o extrato do período página a página, porque o liquidante não filtra por esses campos. Uma única busca pode custar dezenas de requisições ao parceiro e demorar bem mais que o extrato comum.
Ele existe para facilitar consulta pontual, investigação e conciliação manual. Não deve ser abusado e, em hipótese alguma, usado para consulta recorrente ou polling.
- Para acompanhar recebimentos em tempo real, use webhooks
(
pix.in.completed). O evento chega sozinho, na hora, sem custo de varredura. - Para volume ou fechamento, use o extrato comum paginado ou a exportação CSV.
- Prefira sempre o extrato comum quando os filtros nativos bastarem. Recorra a este endpoint só quando precisar de um campo que só ele filtra.
Uso recorrente é detectável e será tratado como abuso, do mesmo modo que o consumo abusivo de consultas DICT.
A chave PIX agora aparece no extrato comum
Antes de recorrer à busca avançada, note que toda linha do extrato passou a
trazer a chave usada na transação, no campo pixKey — tanto aqui quanto no
extrato comum:
O sentido do campo segue a direção do lançamento:
Não confunda com counterParty.pixKey, que descreve a contraparte. Num crédito
o liquidante costuma preencher pixKey e deixar a da contraparte vazia.
Se o que você precisa é apenas saber em que chave cada recebimento caiu, o
extrato comum já responde, e sai muito mais barato: pagine normalmente e leia o
campo. O export CSV/PDF/XLSX (POST /v1/accounts/{accountId}/exports) também
traz pixKey em cada linha. A busca avançada só é necessária quando você
precisa filtrar por ele.
Filtros disponíveis
Todos são opcionais e combinam entre si por E (todas as condições precisam valer).
Duas observações que evitam surpresa:
operation é o filtro mais barato. É o único que o liquidante consegue
aplicar do lado dele, então informá-lo faz a varredura já chegar reduzida.
Quando souber o tipo, informe.
A busca por nome é tolerante. Ignora acento e caixa, e não exige ordem: cada
termo separado por espaço precisa aparecer em algum lugar do nome, em qualquer
ordem. costa miranda e miranda costa acham “Manaire da Costa Miranda”; jose
acha “José”.
Paginação por cursor
Não existe “página 2”. A posição de um lançamento no resultado filtrado não tem relação fixa com a posição dele no extrato bruto, então pular para uma página arbitrária exigiria varrer o período desde o começo outra vez.
Cada chamada gasta um orçamento limitado — um número máximo de páginas do
liquidante e um teto de tempo. Quando o orçamento acaba antes do fim do período,
a resposta traz exhausted: false e um nextCursor:
A resposta:
Repita passando cursor enquanto exhausted for false. Quando vier true, o
período foi varrido até o fim e você tem tudo que casa com o filtro.
Por padrão, os resultados vêm do mais antigo para o mais recente
Sem order, a varredura é crescente e a resposta devolve order: "asc" para
deixar isso explícito.
Isso é o que faz a retomada por cursor ser exata, não uma preferência de apresentação. O cursor é uma posição dentro do extrato do liquidante. Em ordem decrescente, um lançamento que chega no meio da varredura entra no topo e empurra todas as posições seguintes uma casa adiante — a chamada de continuação passaria a apontar para um item já entregue, e você receberia linha repetida. Em ordem crescente, o que chega entra no fim, e nada do que já foi varrido se move.
Como o período default é o dia corrente, a janela quase sempre inclui “agora” — ou seja, esse é o caso comum, não a exceção.
Quero só as mais recentes
Conta com milhares de lançamentos no dia e você precisa do fim do período, não do começo. Dois caminhos, do mais barato ao mais completo:
1. Se os filtros do extrato comum bastam, não use este endpoint.
GET /v1/accounts/{accountId}/statement já devolve do mais recente para o mais
antigo por padrão (order=desc) e aceita size até 500: a primeira página é o
final do dia, a um custo de uma chamada.
2. Se precisa dos filtros avançados (chave PIX, contraparte, valor), use
order=desc, de preferência com occurredAfter marcando a partir de quando
você quer:
A varredura começa pelo lançamento mais recente e para ao cruzar as 17h:
exhausted: true, sem ler a manhã inteira. É isso que torna o modo barato —
occurredAfter em desc é uma fronteira, não só um filtro.
Em desc não existe cursor (mandar um devolve 400 invalid_cursor), pelo
motivo explicado acima: a posição se move quando entra lançamento novo. A
continuação é por tempo. Quando exhausted vier false, a resposta traz
nextOccurredBefore, o instante do último lançamento examinado; repita a
chamada passando esse valor em occurredBefore:
Uma fronteira de tempo não se move quando chega lançamento novo no topo — por
isso ela é segura onde o cursor não é. O preço é pequeno e previsível: como o
limite é inclusivo, lançamentos que dividem o mesmo segundo com a fronteira
podem voltar na chamada seguinte. Dedupe pelo id da linha. Exclusivo seria pior:
pularia esses lançamentos em silêncio, e buraco você não detecta.
O outro custo é de varredura: cada continuação em desc relê do mais recente
até a fronteira antes de avançar, porque o liquidante só pagina por posição.
Para pegar o fim do dia isso é uma ou duas páginas e não importa; para varrer o
dia inteiro de trás para a frente, importa — nesse caso use asc com cursor,
que retoma exatamente de onde parou.
O que occurredAfter / occurredBefore fazem — e o que não fazem
Os dois recortam por horário dentro do período (startDate/endDate continuam
valendo) e são inclusivos. Exigem fuso explícito (-03:00 ou Z): sem ele não
há como saber se “18:00” é Brasília ou UTC, e um erro de três horas aqui passa
despercebido até faltar dinheiro na conciliação.
Só encurtam a varredura quando são a fronteira na direção da varredura:
occurredAfter em desc e occurredBefore em asc param a leitura ao serem
cruzados. No sentido contrário são apenas filtro — o liquidante só aceita data,
então as páginas anteriores ao horário são lidas do mesmo jeito. occurredAfter
em asc, por exemplo, devolve menos linhas mas custa as mesmas páginas.
Uma chamada pode devolver zero itens e um cursor. Significa que o orçamento foi gasto em linhas que não casaram — não que não há o que achar. Continue pelo cursor.
O campo scan mostra o que a chamada custou. Use-o para dimensionar: uma busca
que precisa de muitas continuações é sinal de que o período está largo demais ou
de que o filtro deveria incluir operation.
O cursor pertence à busca
O cursor carrega a impressão digital dos filtros. Se você mudar qualquer um
deles e reaproveitar o cursor, a API responde 400 invalid_cursor — recomece
sem cursor.
Isso é proteção, não capricho: um cursor aplicado a outro filtro apontaria para uma posição sem relação com a nova busca, e o resultado viria silenciosamente errado.
Erros
No painel
A mesma busca está no backoffice, em Advanced search, com os filtros em formulário e o preset “recebimentos por chave” já montado. A tela mostra quantas linhas foram examinadas e marca o resultado como parcial enquanto a varredura não termina.