{"openapi":"3.1.0","info":{"title":"Snabber API","version":"1.0.0","description":"API pública para acessar seus próprios dados financeiros na Snabber. Disponível para planos pagos. Autentique-se com uma chave de API criada em /integrations, enviada no header `Authorization: Bearer snb_live_...`. Uma chave pode estar vinculada a um ou mais workspaces, com um deles marcado como padrão na criação — todo endpoint aceita `workspace_id` para escolher qual consultar; quando omitido, usa o padrão da chave. Use `GET /api/v1/workspaces` para descobrir quais workspaces a chave enxerga e qual é o padrão. Escrita (criar, editar, excluir) depende das permissões ligadas na chave — ver a tag \"Escrita e desfazer\".","contact":{"name":"Snabber","url":"https://snabber.com.br"}},"servers":[{"url":"https://snabber.com.br","description":"Produção"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Transações","description":"Transações financeiras (receitas e despesas)"},{"name":"Contas","description":"Contas bancárias, cartão de crédito e investimento"},{"name":"Categorias","description":"Categorias de transação"},{"name":"Investimentos","description":"Dados de investimentos (aportes/resgates, posições)"},{"name":"Cartão de crédito","description":"Faturas de cartão de crédito"},{"name":"Workspaces","description":"Descoberta dos workspaces que a chave de API está autorizada a acessar"},{"name":"Escrita e desfazer","description":"Criar, editar e excluir dados exige que o dono da chave ligue as permissões \"Permitir criar/editar\" (`write`) e \"Permitir excluir\" (`delete`) na tela de Integrações — toda chave nasce só com leitura — e que o papel dele no workspace permita editar. Exclusões e lotes são em dois passos (preview → `X-Confirmation-Token`). Toda escrita devolve `undo_id`, que desfaz a ação por 30 dias em `POST /api/v1/actions/{undo_id}/undo`. Tetos por chave: 50 itens por chamada; por dia, 500 criações, 1000 edições e 100 exclusões. Transações criadas consomem a cota mensal do plano."}],"paths":{"/api/v1/transactions":{"get":{"summary":"Lista transações do workspace da chave","description":"Retorna transações financeiras (receitas e despesas) do workspace vinculado à chave de API, com filtros por data, categoria, conta e tipo. Paginação por cursor. Cada transação traz `category` (a categoria dela, que pode ser uma subcategoria) e `category_parent` (a categoria pai, ou null). Por padrão omite as categorias que não são entrada/saída real de dinheiro — as marcadas como fora dos totais (`totals_mode` diferente de 'include' em `/api/v1/categories`, ex.: 'Ignorado', 'Pagamento de Cartão de Crédito', 'Investimentos', e as subcategorias delas) — use `include_ignorable_categories=true` para trazê-las.","tags":["Transações"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Data inicial (inclusiva), YYYY-MM-DD"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Data final (inclusiva), YYYY-MM-DD"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filtra por categoria. Repetível (?category=a&category=b) ou CSV (?category=a,b)"},{"name":"include_subcategories","in":"query","schema":{"type":"boolean","default":false},"description":"Com `category`: se true, cada categoria pedida traz também as subcategorias dela (ex.: `category=Transporte` inclui \"Uber\" se for subcategoria de Transporte). Padrão false: nome exato."},{"name":"account","in":"query","schema":{"type":"string"},"description":"Filtra por nome de conta. Repetível ou CSV"},{"name":"type","in":"query","schema":{"type":"string","enum":["income","expense"]},"description":"Filtra por tipo, derivado do sinal do valor"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200},"description":"Máximo de itens por página (até 200)"},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Cursor de paginação retornado em pagination.next_cursor"},{"name":"include_ignorable_categories","in":"query","schema":{"type":"boolean","default":false},"description":"Se true, inclui as categorias que não são entrada/saída real (as fora dos totais, ex.: Ignorado, Pagamento de Cartão de Crédito, Investimentos, e as subcategorias delas). Padrão false: fique de fora ao somar receitas/despesas, a menos que o usuário peça essas categorias explicitamente."}],"responses":{"200":{"description":"Lista de transações","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionList"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Cria uma transação","description":"Cria UMA transação, sem recorrência, na hora (sem preview). Para lotes ou recorrências use `POST /api/v1/transactions/batch`. A conta precisa existir no workspace (nome exato de `GET /api/v1/accounts`); a categoria é criada se não existir. Consome 1 da cota mensal de transações.","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":128},"description":"Opcional. Repetir a requisição com a mesma chave (por 24h) devolve o resultado da primeira em vez de gravar de novo."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionInput"}}}},"responses":{"201":{"description":"Criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransactionsResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions/aggregate":{"get":{"summary":"Agrega transações do workspace da chave por dimensão","description":"Agrupa transações (receitas e despesas) do workspace vinculado à chave de API por uma ou mais dimensões (category, category_parent, account, month, description, partner), somando receita/despesa/saldo por grupo. `category_parent` soma as subcategorias na categoria pai delas; `category` separa cada subcategoria. Aceita os mesmos filtros de `/api/v1/transactions` (from, to, category, include_subcategories, account, type). Não é paginado — varre todo o período pedido até um teto interno de linhas; se excedido, `meta.truncated=true` e o período deve ser reduzido. Por padrão exclui dos totais as categorias que não são entrada/saída real (as fora dos totais, ex.: Ignorado, Pagamento de Cartão de Crédito, Investimentos) — use `include_ignorable_categories=true` para incluí-las (ex.: ao pedir explicitamente o total movimentado em transferências ou investimentos).","tags":["Transações"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Data inicial (inclusiva), YYYY-MM-DD"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Data final (inclusiva), YYYY-MM-DD"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filtra por categoria. Repetível ou CSV"},{"name":"include_subcategories","in":"query","schema":{"type":"boolean","default":false},"description":"Com `category`: se true, cada categoria pedida traz também as subcategorias dela (ex.: `category=Transporte` inclui \"Uber\" se for subcategoria de Transporte). Padrão false: nome exato."},{"name":"account","in":"query","schema":{"type":"string"},"description":"Filtra por nome de conta. Repetível ou CSV"},{"name":"type","in":"query","schema":{"type":"string","enum":["income","expense"]},"description":"Filtra por tipo, derivado do sinal do valor"},{"name":"group_by","in":"query","schema":{"type":"string"},"description":"Dimensão(ões) de agrupamento: category, category_parent, account, month, description, partner. Repetível ou CSV. Padrão: category"},{"name":"top_n","in":"query","schema":{"type":"integer","default":20},"description":"Máximo de buckets quando group_by inclui 'description'; o restante vira um bucket 'Outros'"},{"name":"include_ignorable_categories","in":"query","schema":{"type":"boolean","default":false},"description":"Se true, inclui nos totais as categorias que não são entrada/saída real (as fora dos totais, ex.: Ignorado, Pagamento de Cartão de Crédito, Investimentos). Padrão false."}],"responses":{"200":{"description":"Transações agregadas por grupo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregateResult"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/accounts":{"get":{"summary":"Lista contas bancárias do workspace da chave","description":"Retorna as contas (bancárias, cartão de crédito, investimento) do workspace vinculado à chave de API.","tags":["Contas"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"type","in":"query","schema":{"type":"string","enum":["BANK","CREDIT","INVESTMENT"]},"description":"Filtra por tipo de conta"}],"responses":{"200":{"description":"Lista de contas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountList"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Cria uma conta manual","description":"Conta sem Open Finance: `BANK` ou `CREDIT` (com dias de fechamento e vencimento opcionais).","tags":["Contas","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountInput"}}}},"responses":{"201":{"description":"Criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountWriteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Já existe uma conta com esse nome no workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/categories":{"get":{"summary":"Lista categorias do workspace da chave","description":"Retorna as categorias de transação do workspace vinculado à chave de API, com limite mensal, ícone e grupo de DRE (`dre_group`, quando definido — aplicável apenas a workspaces compartilhados/empresa). Categorias podem ter subcategorias: `parent_id` aponta para a categoria pai (null = raiz), e uma transação pode estar tanto na pai quanto numa subcategoria. `totals_mode` diz como a categoria entra nos totais (só a raiz guarda; a subcategoria herda do pai). Por padrão omite as categorias fora dos totais (ex.: Ignorado, Pagamento de Cartão de Crédito, Investimentos) — use `include_ignorable_categories=true` para trazê-las.","tags":["Categorias"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"include_ignorable_categories","in":"query","schema":{"type":"boolean","default":false},"description":"Se true, inclui as categorias fora dos totais (ex.: Ignorado, Pagamento de Cartão de Crédito, Investimentos, e as subcategorias delas). Padrão false."}],"responses":{"200":{"description":"Lista de categorias","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryList"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Cria uma categoria","description":"Com `parent_id` (uma categoria raiz) vira subcategoria. Nome único no workspace.","tags":["Categorias","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryInput"}}}},"responses":{"201":{"description":"Criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryWriteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Já existe uma categoria com esse nome","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/accounts/balance-history":{"get":{"summary":"Histórico de saldo de uma ou mais contas","description":"Retorna o histórico diário de saldo (`account_balance_history`) de uma ou mais contas do workspace vinculado à chave de API, filtrado por período. Aceita `account_id` repetido (`account_id=1&account_id=2`) ou separado por vírgula (`account_id=1,2`) para trazer várias contas de uma vez; se omitido, traz todas as contas do workspace. Por padrão retorna uma linha por conta/dia (`BalanceHistoryList`); com `group_by=day`, o resultado vem agrupado por data — cada dia traz o último saldo de cada conta pedida, lado a lado, mais `total` somando os saldos do dia (`BalanceHistoryDayList`). Contas informadas precisam pertencer a esse workspace.","tags":["Contas"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","required":false,"schema":{"type":"string"},"description":"Id da conta, ou várias separadas por vírgula (ex: 12,34) ou repetindo o parâmetro (ver `/api/v1/accounts`). Se omitido, traz todas as contas do workspace."},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Data inicial (inclusiva), YYYY-MM-DD"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Data final (inclusiva), YYYY-MM-DD"},{"name":"group_by","in":"query","schema":{"type":"string","enum":["day"]},"description":"Se \"day\", agrupa o resultado por data — cada dia traz o saldo de cada conta pedida lado a lado"}],"responses":{"200":{"description":"Histórico de saldo (BalanceHistoryList, ou BalanceHistoryDayList quando group_by=day)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceHistoryList"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/accounts/realtime-balance":{"get":{"summary":"Consulta o saldo de uma conta em tempo real","description":"Pergunta ao parceiro de Open Finance o saldo atual da conta diretamente na instituição, sem rodar uma sincronização. É uma consulta pura: nada é gravado na Snabber, então `balance`, `provider_updated_at` e o histórico de saldo da conta seguem refletindo a última sincronização — cabe a quem chama decidir o que fazer com esta leitura mais recente. Nem todo conector oferece saldo em tempo real; quando não oferece, o parceiro devolve o saldo da última coleta dele e a resposta traz `is_realtime: false`. O mesmo vale quando a consulta em tempo real falha: em vez de erro, a resposta devolve o último saldo conhecido com `is_realtime: false` e `collected_at` dizendo quando o parceiro coletou aquele número — então sempre confira `is_realtime` antes de tratar o valor como sendo do instante da chamada. Atenção: por vir da instituição naquele instante, um saldo em tempo real pode já refletir um lançamento que ainda não aparece em `/api/v1/transactions`. Cada chamada consulta o parceiro, então use com parcimônia — vale o limite de requisições da sua chave.","tags":["Contas"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","required":true,"schema":{"type":"integer"},"description":"Id da conta conectada via Open Finance (ver `/api/v1/accounts`)"}],"responses":{"200":{"description":"Saldo consultado no parceiro","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeBalance"}}}},"400":{"description":"Parâmetro inválido, ou conta que não é conectada via Open Finance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conexão Open Finance da conta não está mais ativa; é preciso reconectar","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/credit-card-bills":{"get":{"summary":"Lista faturas de cartão de crédito","description":"Retorna as faturas reais que o emissor do cartão reportou via Open Finance (`credit_card_bills`), com o valor total cobrado, datas de fechamento/vencimento, pagamento mínimo, encargos e situação de pagamento. Cada fatura é identificada pelo mês de vencimento (`cycle_month`, YYYY-MM). Só aparecem cartões sincronizados via Open Finance e meses dentro da janela que o banco disponibiliza — cartões manuais não têm fatura real; para esses, use `/api/v1/credit-card-bills/invoice`, que cai na estimativa local. A conta pode ser informada por `account_id` ou pelo nome em `account`; se omitida, traz todos os cartões do workspace.","tags":["Cartão de crédito"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","schema":{"type":"integer"},"description":"Id da conta de cartão de crédito (ver `/api/v1/accounts`)"},{"name":"account","in":"query","schema":{"type":"string"},"description":"Nome exato da conta, alternativa a `account_id`"},{"name":"from_month","in":"query","schema":{"type":"string","example":"2026-01"},"description":"Mês de vencimento inicial (inclusivo), YYYY-MM"},{"name":"to_month","in":"query","schema":{"type":"string","example":"2026-06"},"description":"Mês de vencimento final (inclusivo), YYYY-MM"}],"responses":{"200":{"description":"Lista de faturas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditCardBillList"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/credit-card-bills/invoice":{"get":{"summary":"Fatura de um cartão em um ciclo, detalhada por categoria","description":"Retorna a fatura de um cartão para um ciclo (identificado pelo mês de vencimento, `cycle_month`), quebrada por categoria — por padrão pela categoria principal, com as subcategorias detalhadas em `subcategories` (já incluídas no `total` da principal); `group_by=category` devolve uma linha por categoria/subcategoria, sem hierarquia. Quando existe a fatura real do Open Finance, `source` é `pluggy_bill` e `total` é o valor que o emissor cobrou (o mesmo \"Total da fatura\" que aparece no app), com as transações realmente atribuídas àquela fatura pelo banco; sem fatura real (cartão manual, ciclo fora da janela do banco), `source` é `estimated_payment_date` e `total` é a estimativa local somando as transações cuja data de pagamento cai no mês. `total` inclui categorias que são cobrança real mas não contam como gasto pessoal (`ignorable: true`, ex. \"Ignorado\" e \"Pagamento de Cartão de Crédito\") — para comparar com gasto pessoal efetivo use `effective_total`, nunca `total` sozinho.","tags":["Cartão de crédito"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","schema":{"type":"integer"},"description":"Id da conta de cartão de crédito (ver `/api/v1/accounts`). Obrigatório se `account` não for informado."},{"name":"account","in":"query","schema":{"type":"string"},"description":"Nome exato da conta, alternativa a `account_id`"},{"name":"cycle_month","in":"query","required":true,"schema":{"type":"string","example":"2026-06"},"description":"Mês de vencimento do ciclo, YYYY-MM"},{"name":"group_by","in":"query","schema":{"type":"string","enum":["category_parent","category"],"default":"category_parent"},"description":"`category_parent` (padrão): pela categoria principal, com `subcategories`. `category`: uma linha por categoria da transação (subcategoria separada da principal)."}],"responses":{"200":{"description":"Fatura do ciclo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditCardInvoice"}}}},"400":{"description":"Parâmetro inválido ou conta não informada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/investments/transactions":{"get":{"summary":"Transações (aportes/resgates) de uma conta de investimento","description":"Retorna os aportes e resgates (`investment_movements`) de uma conta de investimento do workspace vinculado à chave de API, filtrado por período. A conta precisa pertencer a esse workspace.","tags":["Investimentos"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","required":true,"schema":{"type":"integer"},"description":"Id da conta de investimento (ver `/api/v1/accounts`)"},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Data inicial (inclusiva), YYYY-MM-DD"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Data final (inclusiva), YYYY-MM-DD"}],"responses":{"200":{"description":"Lista de transações de investimento","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvestmentTransactionList"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/investments/positions":{"get":{"summary":"Posições de uma conta de investimento","description":"Retorna as posições/contratos (`investment_positions`) de uma conta de investimento do workspace vinculado à chave de API — CDB, ações, fundos etc., com saldo, taxas e datas. `from`/`to` filtram por purchase_date/position_date. A conta precisa pertencer a esse workspace.","tags":["Investimentos"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"account_id","in":"query","required":true,"schema":{"type":"integer"},"description":"Id da conta de investimento (ver `/api/v1/accounts`)"},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Data inicial (inclusiva) de purchase_date/position_date, YYYY-MM-DD"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Data final (inclusiva) de purchase_date/position_date, YYYY-MM-DD"}],"responses":{"200":{"description":"Lista de posições de investimento","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvestmentPositionList"}}}},"400":{"description":"Parâmetro inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/workspaces":{"get":{"summary":"Lista os workspaces autorizados para esta chave","description":"Retorna os workspaces que esta chave de API está autorizada a acessar, e qual deles é o padrão (usado pelos demais endpoints quando `workspace_id` não é informado). Consulte antes de passar `workspace_id` explicitamente, para ter certeza de estar apontando para o workspace certo.","tags":["Workspaces"],"responses":{"200":{"description":"Lista de workspaces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceList"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plano do usuário não tem acesso à API (downgrade para free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions/batch":{"post":{"summary":"Cria transações em lote (com confirmação)","description":"Até 50 itens, cada um com recorrência opcional. A primeira chamada responde 409 com o preview (como cada item foi entendido, categorias novas, possíveis duplicatas e `quota` consumida da cota mensal) e um token. Repita com `X-Confirmation-Token` (o corpo pode ir vazio): grava exatamente o que o preview mostrou, tudo ou nada.","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":128},"description":"Opcional. Repetir a requisição com a mesma chave (por 24h) devolve o resultado da primeira em vez de gravar de novo."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/TransactionInput"}}}}}}},"responses":{"201":{"description":"Criadas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransactionsResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions/{id}":{"patch":{"summary":"Edita uma transação","description":"Altera só os campos enviados. Executa na hora e devolve `undo_id`.","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da transação"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionPatch"}}}},"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Transação não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Exclui uma transação (com confirmação)","description":"Primeira chamada: 409 com preview. Transações do Open Finance podem voltar no próximo sync — o preview avisa.","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da transação"},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."}],"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Transação não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions/bulk-delete":{"post":{"summary":"Exclui várias transações (com confirmação)","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transaction_ids"],"properties":{"transaction_ids":{"type":"array","maxItems":50,"items":{"type":"integer"}}}}}}},"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Alguma transação não existe neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/recurrences/{transaction_id}":{"delete":{"summary":"Exclui ocorrências de uma recorrência (com confirmação)","description":"`mode=future`: esta transação e as seguintes da série; `mode=all`: a série inteira.","tags":["Transações","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"transaction_id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id de qualquer transação da série"},{"name":"mode","in":"query","required":true,"schema":{"type":"string","enum":["future","all"]}},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."}],"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/categories/{id}":{"patch":{"summary":"Edita uma categoria","description":"Renomear leva junto as transações da categoria (e desfazer renomeia de volta).","tags":["Categorias","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da categoria"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryInput"}}}},"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryWriteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Categoria não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Exclui uma categoria (com confirmação)","description":"Com transações, exige `reassign_to` (nome da categoria que as recebe). Com subcategorias, exige `unparent_children=true`. Categorias especiais do app não podem ser excluídas.","tags":["Categorias","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da categoria"},{"name":"reassign_to","in":"query","schema":{"type":"string"}},{"name":"unparent_children","in":"query","schema":{"type":"boolean"}},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."}],"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/accounts/{id}":{"patch":{"summary":"Edita uma conta","description":"`name` (as transações acompanham) e/ou `balance` (só contas manuais).","tags":["Contas","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da conta"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"balance":{"type":"number"}}}}}},"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountWriteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Conta não encontrada neste workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Exclui uma conta (com confirmação)","description":"Recusa conta com transações ou com conexão Open Finance ativa.","tags":["Contas","Escrita e desfazer"],"parameters":[{"$ref":"#/components/parameters/WorkspaceId"},{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Id da conta"},{"name":"X-Confirmation-Token","in":"header","schema":{"type":"string"},"description":"Token devolvido pela primeira chamada (409 CONFIRMATION_REQUIRED). Envie só depois de confirmar com quem pediu a ação."}],"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nada foi gravado: a ação precisa de confirmação. O corpo traz `preview` e `confirmation_token`; repita a mesma requisição com o header `X-Confirmation-Token` (vale 5 minutos, uma vez). Também usado para `INVALID_CONFIRMATION`, `STALE_CONFIRMATION` (os dados mudaram desde o preview) e conflitos como duplicata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationRequired"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/actions/{undo_id}/undo":{"post":{"summary":"Desfaz uma ação","description":"Desfaz uma ação feita por esta chave, por até 30 dias. Criações são apagadas; exclusões e edições voltam ao estado anterior. Itens que não puderem voltar aparecem em `skipped`. A cota mensal usada não volta.","tags":["Escrita e desfazer"],"parameters":[{"name":"undo_id","in":"path","required":true,"schema":{"type":"integer"},"description":"`undo_id` devolvido pela ação"}],"responses":{"200":{"description":"Feito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoResult"}}}},"401":{"description":"Chave de API ausente, inválida, revogada ou expirada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`INSUFFICIENT_SCOPE` (chave sem a permissão de escrita/exclusão), `WORKSPACE_READ_ONLY` (seu papel no workspace é somente leitura) ou `TRANSACTION_QUOTA_EXCEEDED` (cota mensal de transações)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Ação não encontrada para esta chave","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`ALREADY_UNDONE` ou `UNDO_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Dados inválidos (`details.field` diz qual), conta inexistente no workspace (`details.available`), etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limite de requisições ou teto diário de escrita da chave (`DAILY_WRITE_LIMIT`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Escrita pela API temporariamente desativada (`WRITES_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"parameters":{"WorkspaceId":{"name":"workspace_id","in":"query","schema":{"type":"integer"},"description":"Workspace a consultar, entre os autorizados para esta chave (ver `GET /api/v1/workspaces`). Se omitido, usa o workspace padrão da chave. Um id fora do conjunto autorizado resulta em `400 INVALID_WORKSPACE`. Só é possível autorizar (em /integrations) um workspace do qual o dono da chave já é membro — para incluir dados de um workspace de outra pessoa, ela precisa primeiro compartilhar esse workspace com você (convite em /workspaces), não basta saber o id."}},"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"snb_live_*","description":"Chave de API gerada em /integrations. Envie como `Authorization: Bearer snb_live_...`"}},"schemas":{"Transaction":{"type":"object","properties":{"id":{"type":"integer","example":38578},"date":{"type":"string","format":"date","example":"2026-04-05"},"time":{"type":["string","null"],"example":"14:32:00"},"description":{"type":["string","null"],"example":"Mercado"},"amount":{"type":["number","null"],"example":-150.5},"currency_code":{"type":"string","example":"BRL"},"type":{"type":"string","enum":["income","expense"]},"category":{"type":"string","example":"Uber"},"category_parent":{"type":["string","null"],"example":"Transporte","description":"Categoria pai de `category`, quando `category` é uma subcategoria; null quando é raiz."},"account":{"type":"string","example":"Bradesco"},"comment":{"type":["string","null"]},"paid":{"type":"boolean"},"payment_date":{"type":["string","null"],"format":"date","description":"Data estimada de pagamento da fatura para transações de cartão de crédito (null nas demais contas). É cálculo nosso a partir do dia de fechamento/vencimento cadastrado no cartão — não vem da instituição. Ver `bill_id` para a ordem de confiabilidade ao associar uma transação a uma fatura"},"installment_number":{"type":["integer","null"],"example":3,"description":"Número desta parcela numa compra parcelada no cartão (o \"3\" de \"3/10\"), como informado pela instituição. null quando a transação não é parcelada ou a instituição não informou"},"total_installments":{"type":["integer","null"],"example":10,"description":"Total de parcelas da compra (o \"10\" de \"3/10\"). `amount` é o valor só desta parcela, não da compra inteira. null quando a transação não é parcelada ou a instituição não informou"},"bill_id":{"type":["string","null"],"example":"a3f1c0de-9b2e-4d77-8f10-2c5e1b7a4d90","description":"Fatura à qual a instituição atribuiu esta transação. Casa com `id` de /v1/credit-card-bills. Identificador opaco: não presuma formato. Como associar uma transação a uma fatura, em ordem de confiabilidade: 1) `bill_id` — quando presente, é vínculo confirmado pela instituição, que só o emite depois que a fatura fecha. Use sempre que houver. 2) `bill_forecast_date` — quando `bill_id` é null, casa com `closing_month` da fatura. É a previsão da instituição enquanto o ciclo está aberto e pode mudar até fechar. 3) `payment_date` — quando os dois acima são null, é o que resta para situar a transação num ciclo (contra `cycle_month` da fatura), mas é estimativa nossa, sem confirmação da instituição. Não trate uma fatura reconstruída só por `payment_date` como obrigação confirmada. Os dois primeiros são sempre null em cartão cadastrado manualmente, que não tem fatura da instituição"},"bill_forecast_date":{"type":["string","null"],"example":"2026-06","description":"Mês de fechamento (\"YYYY-MM\") previsto pela instituição enquanto a fatura está aberta. Casa com `closing_month` da fatura. Ver `bill_id`"},"source":{"type":"string","example":"open_finance","description":"'open_finance' quando veio do banco pelo Open Finance; senão a origem gravada: 'manual', 'snabby' (IA do app), 'telegram', 'api'"},"synced":{"type":"boolean","description":"true quando veio do Open Finance — pode ser reescrita ou voltar no próximo sync se for excluída"},"partner_initials":{"type":["string","null"],"example":"JS","description":"Iniciais do membro do workspace que lançou/sincronizou a transação; null quando é do próprio dono. Por privacidade o nome completo não é exposto"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Account":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"account_number":{"type":["string","null"]},"type":{"type":["string","null"],"example":"BANK"},"subtype":{"type":["string","null"]},"balance":{"type":["number","null"]},"currency_code":{"type":"string","example":"BRL"},"credit_limit":{"type":["number","null"]},"available_credit_limit":{"type":["number","null"]},"statement_closing_date":{"type":["integer","null"]},"payment_due_date":{"type":["integer","null"]},"institution":{"type":"object","properties":{"name":{"type":["string","null"]},"logo_url":{"type":["string","null"]}}},"is_connected":{"type":"boolean"},"provider_updated_at":{"type":["string","null"],"format":"date-time","description":"Quando o parceiro de Open Finance atualizou os dados desta conta junto à instituição. É este o campo que indica a idade do saldo — `updated_at` diz apenas quando o registro foi gravado na Snabber, o que pode ser bem depois. Nulo em conta manual/importada ou enquanto a conexão não passou por uma sincronização após a introdução do campo. Ressalva: é a informação que o parceiro reporta sobre a própria atualização dele; a instituição ainda pode ter servido dado mais antigo por trás disso."},"sync":{"type":["object","null"],"description":"Estado da sincronização Open Finance desta conta. Nulo em conta manual/importada. Use junto com `provider_updated_at`: este bloco diz se o dado está estável, aquele campo diz de quando ele é.","properties":{"state":{"type":"string","enum":["ok","syncing","error","needs_reconnection"],"description":"`ok` = em dia, nada em andamento. `syncing` = sincronização rodando agora, o saldo pode estar em trânsito. `error` = a última sincronização não completou (falhou ou foi interrompida no meio), então o saldo pode estar gravado sem que as transações tenham chegado inteiras; este estado permanece até que uma sincronização conclua com sucesso — na prática, até a próxima atualização automática do parceiro disparar uma nova — então pode continuar por um tempo numa conexão que já voltou a funcionar. Leia junto com `last_completed_at` para saber de quando é o último ciclo completo. `needs_reconnection` = a conexão precisa de ação do usuário no app, e o dado vai envelhecer até isso ser feito. Valores podem ser acrescentados no futuro: trate um valor desconhecido como `ok`, que é o comportamento padrão desta API."},"last_completed_at":{"type":["string","null"],"format":"date-time","description":"Última sincronização concluída com sucesso. Só avança quando a sincronização foi até o fim e importou dados — uma que morreu no meio não mexe neste carimbo, então ele nunca indica um sucesso que não houve."}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"RealtimeBalance":{"type":"object","properties":{"data":{"type":"object","properties":{"account_id":{"type":"integer"},"balance":{"type":"number"},"is_realtime":{"type":"boolean","description":"false = o valor devolvido não é do instante da chamada, e sim o último saldo conhecido — porque o conector não oferece consulta em tempo real ou porque ela falhou agora. Nesse caso, use `collected_at` para saber de quando ele é."},"collected_at":{"type":["string","null"],"format":"date-time","description":"Quando o parceiro coletou o saldo devolvido, junto à instituição. Nulo quando `is_realtime` é true (aí o saldo é do momento da consulta) ou quando a conexão ainda não sincronizou desde a versão 7.4.2."},"queried_at":{"type":"string","format":"date-time","description":"Momento desta consulta"}}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"Pagination":{"type":"object","properties":{"limit":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"TransactionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"AggregateBucket":{"type":"object","properties":{"keys":{"type":"object","description":"Chaves do grupo, uma por dimensão pedida em group_by","properties":{"category":{"type":"string"},"category_parent":{"type":"string","description":"Categoria pai (ou a própria, se for raiz)"},"account":{"type":"string"},"month":{"type":"string","example":"2026-04"},"description":{"type":"string"}}},"income":{"type":"number"},"expense":{"type":"number"},"net":{"type":"number"},"count":{"type":"integer"}}},"AggregateResult":{"type":"object","properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/AggregateBucket"}},"totals":{"type":"object","properties":{"income":{"type":"number"},"expense":{"type":"number"},"net":{"type":"number"},"count":{"type":"integer"}}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"},"scanned_count":{"type":"integer"},"truncated":{"type":"boolean","description":"true se o período excedeu o teto interno de linhas escaneadas"}}}}},"AccountList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Account"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"Category":{"type":"object","properties":{"id":{"type":"integer"},"category":{"type":"string","example":"Alimentação"},"monthly_limit":{"type":["number","null"]},"icon_url":{"type":["string","null"]},"dre_group":{"type":["string","null"],"enum":["receita_bruta","deducoes","custos","despesas_operacionais","resultado_financeiro","nao_operacional",null],"description":"Grupo do DRE, apenas quando definido e o workspace suporta DRE (compartilhado/empresa)"},"parent_id":{"type":["integer","null"],"description":"Id da categoria pai, quando esta é uma subcategoria; null para categoria raiz."},"totals_mode":{"type":"string","enum":["include","toggle","never","cash_only"],"description":"Como a categoria entra nos totais: 'include' normal; 'toggle' fora por padrão (volta com include_ignorable_categories); 'never' nunca soma; 'cash_only' só na visão de caixa (pagamento de fatura). Só a categoria raiz guarda; a subcategoria herda o do pai (e aqui vem sempre include)."}}},"CategoryList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"BalanceHistoryEntry":{"type":"object","properties":{"id":{"type":"integer"},"account_id":{"type":"integer"},"date":{"type":"string","format":"date"},"balance":{"type":["number","null"]},"currency_code":{"type":"string","example":"BRL"},"updated_at":{"type":"string","format":"date-time"}}},"BalanceHistoryList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BalanceHistoryEntry"}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"},"account_id":{"description":"Id único, ou lista de ids quando mais de uma conta foi pedida","oneOf":[{"type":"integer"},{"type":"array","items":{"type":"integer"}}]}}}}},"BalanceHistoryDayEntry":{"type":"object","description":"Um dia, com o último saldo de cada conta pedida naquele dia (resposta de group_by=day). Uma conta sem snapshot exatamente nesse dia repete o último saldo conhecido de um dia anterior (`carried_forward: true`, `as_of_date` = data desse saldo). `total` soma apenas as contas em `total_currency_code` (moeda preferida do usuário) — contas em outra moeda aparecem em `accounts` mas ficam fora do `total`, pois somar moedas diferentes exige uma taxa de conversão.","properties":{"date":{"type":"string","format":"date"},"total":{"type":"number","description":"Soma dos saldos do dia, apenas contas em total_currency_code"},"total_currency_code":{"type":"string","example":"BRL"},"accounts":{"type":"array","items":{"type":"object","properties":{"account_id":{"type":"integer"},"balance":{"type":["number","null"]},"currency_code":{"type":"string","example":"BRL"},"updated_at":{"type":"string","format":"date-time"},"carried_forward":{"type":"boolean","description":"true se este saldo foi repetido de um dia anterior (sem snapshot nesse dia exato)"},"as_of_date":{"type":"string","format":"date","description":"Data do saldo usado — igual a `date` quando carried_forward é false"}}}}}},"BalanceHistoryDayList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BalanceHistoryDayEntry"}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"},"account_id":{"type":"array","items":{"type":"integer"}}}}}},"InvestmentTransaction":{"type":"object","properties":{"id":{"type":"integer"},"date":{"type":"string","format":"date"},"type":{"type":"string","enum":["APPLICATION","WITHDRAWAL"],"description":"APPLICATION = aporte, WITHDRAWAL = resgate"},"amount":{"type":"number","description":"Sempre positivo; o sinal vem de `type`"},"quantity":{"type":["number","null"],"description":"Cotas/ações/títulos movimentados, quando informado"},"unit_value":{"type":["number","null"],"description":"Preço unitário na data, quando informado"},"currency_code":{"type":"string","example":"BRL"},"source":{"type":"string","enum":["pluggy","manual"]},"raw_type":{"type":["string","null"],"description":"Valor cru vindo da Pluggy, para debug"},"position_id":{"type":["integer","null"],"description":"Posição associada, quando aplicável"},"ignored":{"type":"boolean","description":"true se marcada manualmente como duplicata e excluída dos cálculos de rentabilidade"}}},"InvestmentTransactionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvestmentTransaction"}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"},"account_id":{"type":"integer"}}}}},"InvestmentPosition":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"code":{"type":["string","null"]},"type":{"type":["string","null"]},"subtype":{"type":["string","null"]},"status":{"type":["string","null"]},"amount_original":{"type":["number","null"]},"amount_withdrawal":{"type":["number","null"]},"amount_profit":{"type":["number","null"]},"balance":{"type":["number","null"]},"position_date":{"type":["string","null"],"format":"date"},"purchase_date":{"type":["string","null"],"format":"date"},"due_date":{"type":["string","null"],"format":"date"},"rate":{"type":["number","null"]},"rate_type":{"type":["string","null"]},"fixed_annual_rate":{"type":["number","null"]},"annual_rate":{"type":["number","null"]},"issuer":{"type":["string","null"]},"currency_code":{"type":"string","example":"BRL"},"updated_at":{"type":"string","format":"date-time"},"closed_at":{"type":["string","null"],"format":"date-time","description":"null = posição ainda aberta"},"ignored":{"type":"boolean","description":"true se marcada manualmente como ignorada nos cálculos de rentabilidade"}}},"InvestmentPositionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvestmentPosition"}},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"},"account_id":{"type":"integer"}}}}},"CreditCardBill":{"type":"object","description":"Fatura real reportada pelo emissor do cartão via Open Finance.","properties":{"id":{"type":"string","example":"a3f1c0de-9b2e-4d77-8f10-2c5e1b7a4d90","description":"Identificador da fatura na instituição. Casa com `bill_id` das transações em /v1/transactions — é o vínculo transação↔fatura mais confiável. Opaco: não presuma formato"},"account_id":{"type":"integer"},"account":{"type":"string","example":"Nubank"},"cycle_month":{"type":"string","example":"2026-06","description":"Mês de vencimento — a chave que identifica a fatura"},"closing_month":{"type":"string","example":"2026-05","description":"Mês de FECHAMENTO do ciclo (\"YYYY-MM\"). Casa com `bill_forecast_date` das transações. Distinto de `cycle_month` (vencimento): quando o dia de vencimento é anterior ao de fechamento, o vencimento cai no mês seguinte"},"due_date":{"type":["string","null"],"format":"date"},"closing_date":{"type":["string","null"],"format":"date","description":"null enquanto a fatura não fechou"},"is_closed":{"type":"boolean"},"total_amount":{"type":["number","null"],"description":"Valor total cobrado pelo emissor","example":1847.32},"currency_code":{"type":["string","null"],"example":"BRL"},"minimum_payment_amount":{"type":["number","null"]},"finance_charges_total":{"type":["number","null"],"description":"Soma dos encargos/juros reportados"},"allows_installments":{"type":["boolean","null"]},"payment_status":{"type":["string","null"],"enum":["paid","partial","open","due","no_charge","unknown",null],"description":"paid = quitada, partial = paga parcialmente, open = ainda aberta, due = fechada e a vencer, no_charge = sem cobrança, unknown = sem evidência de pagamento"},"paid_amount":{"type":["number","null"]},"paid_at":{"type":["string","null"],"format":"date"},"payment_mode":{"type":["string","null"]},"payment_value_type":{"type":["string","null"]}}},"CreditCardBillList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CreditCardBill"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"CreditCardInvoiceCategory":{"type":"object","properties":{"category":{"type":"string","example":"Mercado"},"total":{"type":"number","description":"Soma das despesas da categoria nessa fatura, positiva"},"count":{"type":"integer"},"ignorable":{"type":"boolean","description":"true para cobranças reais que não contam como gasto pessoal (Ignorado, Pagamento de Cartão de Crédito, Investimentos, Transferências Entre Contas Próprias, e as subcategorias delas)"},"subcategories":{"type":"array","description":"Só com group_by=category_parent e quando alguma subcategoria teve gasto: o gasto de cada subcategoria, já incluído em `total`. `total` menos a soma delas é o que foi lançado direto na categoria principal.","items":{"type":"object","properties":{"category":{"type":"string","example":"Uber"},"total":{"type":"number"},"count":{"type":"integer"}}}}}},"CreditCardInvoice":{"type":"object","properties":{"account":{"type":"string","example":"Nubank"},"cycle":{"type":"object","properties":{"month":{"type":"string","example":"2026-06"},"closing_day":{"type":["integer","null"],"description":"Dia do mês em que o ciclo fecha, configurado na conta"},"due_day":{"type":["integer","null"],"description":"Dia do mês do vencimento, configurado na conta"}}},"source":{"type":"string","enum":["pluggy_bill","estimated_payment_date"],"description":"pluggy_bill = total real do emissor; estimated_payment_date = estimativa local por data de pagamento"},"bill":{"description":"Dados da fatura real; null quando source é estimated_payment_date","oneOf":[{"$ref":"#/components/schemas/CreditCardBill"},{"type":"null"}]},"categories":{"type":"array","items":{"$ref":"#/components/schemas/CreditCardInvoiceCategory"}},"total":{"type":"number","description":"Total da fatura, incluindo as categorias ignorable"},"ignored_total":{"type":"number","description":"Parte do total nas categorias ignorable"},"effective_total":{"type":"number","description":"total - ignored_total: o gasto pessoal efetivo da fatura"},"transaction_count":{"type":"integer"},"meta":{"type":"object","properties":{"workspace_id":{"type":"integer"}}}}},"Workspace":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"is_default":{"type":"boolean","description":"Workspace usado quando um endpoint não recebe `workspace_id` explicitamente"}}},"WorkspaceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}},"meta":{"type":"object","properties":{"default_workspace_id":{"type":"integer"}}}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"INVALID_API_KEY"},"message":{"type":"string"}}}}},"TransactionInput":{"type":"object","required":["date","description","amount","category","account"],"properties":{"date":{"type":"string","format":"date"},"description":{"type":"string","maxLength":255},"amount":{"type":"number","description":"Negativo = despesa; positivo = receita"},"category":{"type":"string"},"account":{"type":"string","description":"Nome exato de uma conta do workspace"},"comment":{"type":"string","maxLength":255},"paid":{"type":"boolean","description":"Padrão: true até hoje, false para datas futuras"},"recurrence":{"type":"object","description":"Só em /transactions/batch","properties":{"frequency":{"type":"string","enum":["weekly","monthly","yearly"]},"count":{"type":"integer","minimum":2,"maximum":99}}}}},"TransactionPatch":{"type":"object","properties":{"date":{"type":"string","format":"date"},"description":{"type":"string"},"amount":{"type":"number"},"category":{"type":"string"},"comment":{"type":"string"},"paid":{"type":"boolean"},"account":{"type":"string"}}},"CategoryInput":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"monthly_limit":{"type":["number","null"]},"parent_id":{"type":["integer","null"]},"totals_mode":{"type":"string","enum":["include","toggle","never","cash_only"]}}},"AccountInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100},"type":{"type":"string","enum":["BANK","CREDIT"]},"balance":{"type":"number"},"currency_code":{"type":"string","example":"BRL"},"statement_closing_date":{"type":"integer","minimum":1,"maximum":31},"payment_due_date":{"type":"integer","minimum":1,"maximum":31}}},"ConfirmationRequired":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"CONFIRMATION_REQUIRED"},"message":{"type":"string"}}},"preview":{"type":"object","description":"O que vai acontecer, item a item, com avisos"},"confirmation_token":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"instructions":{"type":"string"}}},"CreateTransactionsResult":{"type":"object","properties":{"status":{"type":"string","example":"done"},"replayed":{"type":"boolean","description":"true quando veio de um Idempotency-Key já usado"},"undo_id":{"type":"integer"},"count":{"type":"integer"},"transaction_ids":{"type":"array","items":{"type":"integer"}},"quota_remaining":{"type":"integer"}}},"UpdateResult":{"type":"object","properties":{"status":{"type":"string"},"undo_id":{"type":"integer"},"transaction":{"type":"object"}}},"DeleteResult":{"type":"object","properties":{"status":{"type":"string"},"undo_id":{"type":"integer"},"deleted":{"type":"integer"}}},"CategoryWriteResult":{"type":"object","properties":{"status":{"type":"string"},"undo_id":{"type":"integer"},"category":{"type":"object"},"renamed_transactions":{"type":"integer"}}},"AccountWriteResult":{"type":"object","properties":{"status":{"type":"string"},"undo_id":{"type":"integer"},"account":{"type":"object"},"renamed_transactions":{"type":"integer"}}},"UndoResult":{"type":"object","properties":{"status":{"type":"string"},"undo_id":{"type":"integer"},"restored":{"type":"integer"},"deleted":{"type":"integer"},"skipped":{"type":"array","items":{"type":"object","properties":{"table":{"type":"string"},"id":{"type":"integer"},"reason":{"type":"string"}}}}}}}}}