Openi DeveloperDeveloper

Filtros, ordenação e busca

Como filtrar por qualquer campo, combinar condições, ordenar, buscar e paginar nos endpoints da Business API.

Todos os endpoints de listagem da Business API aceitam o mesmo formato de filtro. Você filtra pelos mesmos nomes de campo que aparecem na resposta — datas, valores, textos, status e campos personalizados.

ParâmetroFormatoDescrição
filtersJSON (URL-encoded)Lista de condições { id, operator, value }
joinOperatorand | orComo as condições de filters se combinam (padrão: and)
sortJSON (URL-encoded)Lista de ordenações { id, desc }
searchtextoBusca livre (apenas onde indicado)

Cada página de endpoint tem a seção Campos filtráveis com a lista exata de campos, o tipo de cada um e quais aceitam ordenação.

Para recortar pela data principal do endpoint, use from/to — mais simples e igual em todos os endpoints (veja Período). filters serve para qualquer outro campo, inclusive outras datas.

Formato de um filtro

[
  { "id": "amount", "operator": "gte", "value": 1000 },
  { "id": "transactionAt", "operator": "isBetween", "value": ["2026-08-01", "2026-08-31"] },
  { "id": "type", "operator": "eq", "value": "DEBIT" }
]
  • id: nome do campo, igual ao da resposta
  • operator: um dos operadores suportados pelo tipo do campo (tabela abaixo)
  • value: string, número ou lista, conforme o operador — omitido em isEmpty / isNotEmpty

Como filters e sort são JSON dentro da query string, o valor precisa ser URL-encoded:

curl -G "https://api-business.openi.com.br/api/v1/companies/{companyId}/bank-accounts/transactions" \
  -H "Authorization: Bearer oak_368ba506f7b2_9f2c..." \
  --data-urlencode 'from=2026-08-01' \
  --data-urlencode 'filters=[{"id":"amount","operator":"lte","value":-1000},{"id":"operationType","operator":"inArray","value":["PIX","TED"]}]' \
  --data-urlencode 'sort=[{"id":"transactionAt","desc":false}]' \
  --data-urlencode 'perPage=100'
const params = new URLSearchParams({
  from: "2026-08-01",
  filters: JSON.stringify([
    { id: "amount", operator: "lte", value: -1000 },
    { id: "operationType", operator: "inArray", value: ["PIX", "TED"] },
  ]),
  sort: JSON.stringify([{ id: "transactionAt", desc: false }]),
  perPage: "100",
});

const res = await fetch(
  `https://api-business.openi.com.br/api/v1/companies/${companyId}/bank-accounts/transactions?${params}`,
  { headers: { Authorization: `Bearer ${apiKey}` } },
);

URLSearchParams já faz o encoding. Não é preciso informar variant nem filterId — o tipo do campo é conhecido pela API.

Tipos de campo e operadores

TipoExemplosOperadores
textodescription, nameiLike, notILike, eq, ne, inArray, notInArray, isEmpty, isNotEmpty
númeroamount (transações), rate, quantityeq, ne, lt, lte, gt, gte, isBetween, isEmpty, isNotEmpty
valornetValue, currentNetAmountmesmos operadores de número
datatransactionAt, createdAt, placedAteq, ne, lt, lte, gt, gte, isBetween, isRelativeToToday, isEmpty, isNotEmpty
enumstatus, type, origineq, ne, inArray, notInArray, isEmpty, isNotEmpty
uuidid, accountId, investmentIdmesmos operadores de enum
campo personalizadoid (uuid) do campomesmos operadores de texto
OperadorSignificadovalue
eq / neigual / diferentevalor único
lt / ltemenor / menor ou igualvalor único
gt / gtemaior / maior ou igualvalor único
isBetweenentre dois valores, inclusivo[inicio, fim]
iLike / notILikecontém / não contém o texto, sem diferenciar maiúsculastexto
inArray / notInArrayé / não é um dos valoreslista não vazia
isEmpty / isNotEmptyvazio (nulo ou "") / preenchido—
isRelativeToTodayjanela relativa à data de hoje"-7 days", "-1 weeks", "-1 months"

Datas

  • YYYY-MM-DD representa o dia inteiro em UTC: eq "2026-08-01" casa qualquer instante do dia; lte "2026-08-31" inclui todo o dia 31; gt "2026-08-31" começa em 01/09.
  • Data-hora ISO 8601 (2026-08-01T12:30:00-03:00, 2026-08-01T15:30:00Z) compara o instante exato.
  • isBetween com ["2026-08-01", "2026-08-31"] vai do início do primeiro dia ao fim do último.
  • isRelativeToToday recebe "<N> days|weeks|months" e seleciona uma janela que começa em hoje + N: days cobre 1 dia, weeks 7 dias e months 30 dias. Ex.: "-1 weeks" são os 7 dias anteriores a hoje. Para "desde uma data", prefira gte.

Outros formatos (01/08/2026, timestamps numéricos) retornam 400.

Enums e ids

Campos enum com lista fixa de valores (ex.: type, status, classificationStatus) só aceitam os valores documentados na página do endpoint — um valor fora da lista retorna 400 com os valores aceitos, em vez de uma lista vazia. Campos uuid exigem um uuid válido.

Valores

Números e valores monetários usam ponto como separador decimal e podem ir como número ou string (1500.5 ou "1500.50"), sem símbolo de moeda — o mesmo formato das respostas. Nas transações bancárias amount tem sinal: positivo para entradas, negativo para saídas — para "saídas acima de R$ 1.000" use {"id":"amount","operator":"lte","value":-1000}, ou combine type = DEBIT com o valor.

Campos personalizados

Nos endpoints de lançamentos, o id de um campo personalizado (uuid) também é um campo filtrável e ordenável. Os ids e os valores já usados vêm do endpoint de atributos (bancários, investimentos):

[{ "id": "0d9e1f2a-3b4c-4d5e-6f7a-8b9c0d1e2f3a", "operator": "inArray", "value": ["Filial SP", "Filial RJ"] }]

Valores de campos personalizados são sempre comparados como texto.

Combinando condições

joinOperator vale para todas as condições de filters — não há agrupamento. Com or, basta uma condição ser verdadeira:

filters=[{"id":"operationType","operator":"eq","value":"PIX"},{"id":"operationType","operator":"eq","value":"TED"}]
joinOperator=or

Para "um de vários valores" com outras condições em and, use inArray no lugar de or:

[
  { "id": "operationType", "operator": "inArray", "value": ["PIX", "TED"] },
  { "id": "amount", "operator": "gte", "value": 1000 }
]

Parâmetros de escopo (accountId, investmentId) e o período (from/to) sempre restringem o resultado, independentemente de joinOperator.

Ordenação

sort=[{"id":"transactionAt","desc":false}]
  • desc: true para decrescente (padrão false)
  • Vários critérios são aplicados na ordem informada
  • Nem todo campo é ordenável — cada endpoint lista os seus. Sem sort, cada endpoint usa sua ordem padrão (documentada na página)

Busca

Onde disponível, search procura o termo nos principais campos de texto (descrição, contraparte, documento...), sem diferenciar maiúsculas. Documentos formatados (12.345.678/0001-90) também encontram o valor sem máscara. A busca é sempre combinada em and com filters.

Paginação

EndpointParâmetrosResposta
Transações, Transações por diapage, perPage (1–500, padrão 10)pagination: { page, limit, totalPages }
Lançamentos bancários e de investimentospage, perPage (1–500, padrão 10)pagination: { totalRecords, totalPages, hasMore }
Investimentospage, perPage (1–500, padrão 10)meta: { page, perPage, total, totalPages }
Contas, Fluxo de caixa, Campos personalizados—lista completa

Nos lançamentos:

  • hasMore está sempre presente e indica se existe uma próxima página. Para percorrer tudo, avance page enquanto hasMore for true.
  • A contagem para 100 páginas à frente da página pedida. Quando o resultado passa disso, totalRecords e totalPages vêm null — o total ainda não é conhecido. Ao se aproximar do fim, eles voltam a ser o total exato.
// página 1 de um conjunto grande (perPage=500)
"pagination": { "totalRecords": null, "totalPages": null, "hasMore": true }

// página 150 — dentro das 100 páginas finais
"pagination": { "totalRecords": 111599, "totalPages": 224, "hasMore": true }

// última página
"pagination": { "totalRecords": 111599, "totalPages": 224, "hasMore": false }

Erros

Filtros inválidos retornam 400 com a causa na mensagem — nunca são ignorados silenciosamente:

{
  "status": "error",
  "message": "filters.0.operator: operator \"iLike\" is not supported for \"amount\". Use one of: eq, ne, lt, lte, gt, gte, isBetween, isEmpty, isNotEmpty",
  "cause": {
    "target": "query",
    "issues": [
      {
        "path": "filters.0.operator",
        "code": "custom",
        "message": "operator \"iLike\" is not supported for \"amount\". Use one of: eq, ne, lt, lte, gt, gte, isBetween, isEmpty, isNotEmpty"
      }
    ]
  }
}
CausaExemplo de mensagem
Período inválido ou invertidofrom: must be an ISO 8601 date (YYYY-MM-DD) or date-time, from: must not be after to
Campo inexistenteunknown filter field "saldo". Filterable fields: ...
Operador não suportado pelo tipooperator "iLike" is not supported for "amount"
Valor em formato errado"transactionAt" with "eq" expects an ISO 8601 date (YYYY-MM-DD) or date-time
Valor fora da lista do enum"status" with "eq" expects one of: POSTED, PENDING
filters / sort não é JSON válidomust be a URL-encoded JSON array
Campo não ordenávelunknown sort field "description". Sortable fields: transactionAt
search num endpoint sem buscathis endpoint does not support search

On this page