Início rápido
Antes de começar, você precisa de uma conta da Era com pelo menos uma instituição conectada: sem conexão, esses endpoints não têm o que devolver.
- 1
Entre na Era e conecte uma instituição, se ainda não tiver feito isso.
- 2
Abra suas chaves de API no painel e crie uma. Todos os escopos vêm marcados, então desmarque os que você não precisa — para esses endpoints sobra banking:read. Você também escolhe uma validade; não existe opção de nunca expirar.
- 3
Copie a chave. Ela aparece uma vez só, e não conseguimos mostrar de novo. Copie-a e guarde-a em um lugar seguro, como um gerenciador de segredos. Se você perder uma chave, não pode vê-la de novo. Crie uma nova no lugar dela.
- 4
Mande no cabeçalho junto com a sua requisição.
cURL
curl "https://forge.era.app/api/banking/transactions?page=1&pageSize=20" \
-H "X-API-Key: fmk_your_key_here"
Resposta · 200
{
"transactions": [ … ],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 412,
"totalPages": 21
},
"historyWindowApplied": true,
"historyWindowFloorDate": "2026-06-28",
"historyWindowHiddenCount": 137,
"historyWindowEarliestDate": "2024-03-02",
"historyWindowDegraded": false
}
APIs disponíveis
A API da Era inclui as seguintes APIs:
- GET/banking/accounts
Cada conta que você pode ver, em todas as instituições conectadas.
- GET/banking/accounts/{accountId}/balance
O saldo de uma conta, com os campos de crédito preenchidos se for um passivo.
- GET/banking/accounts/summary
Os totais de todas as contas que você pode ver.
- GET/banking/transactions
Suas transações, uma página de cada vez.
- PUT/banking/transactions/{id}
Mudar uma transação
- PUT/banking/transactions/bulk
Mudar até 100 de uma vez
- GET/banking/categories
Toda a taxonomia de categorias, com as subcategorias aninhadas.
- POST/banking/categories
Adicionar uma categoria
- GET/banking/tags
Todas as tags da sua conta, em uma única resposta.
- POST/banking/tags
Criar uma etiqueta
Autenticação
Envie sua chave de uma das duas formas:
| Método | Credencial |
|---|---|
| Cabeçalho | X-API-Key: fmk_your_key_here |
| Token Bearer | Authorization: Bearer fmk_your_key_here |
Toda requisição é criptografada com TLS.
As chaves expiram, e você escolhe em quanto tempo ao criar. O máximo é 90 dias no plano gratuito e 365 num pago — não existe opção de nunca expirar, então o que você construir em cima disso precisa de um plano para rotacionar a chave antes que ela vença.
Cabeçalhos de resposta
Toda resposta inclui:
| Cabeçalho | Descrição |
|---|---|
| fly-request-id | Um identificador único da requisição. Inclua-o ao entrar em contato com o suporte sobre uma requisição específica — veja ID da solicitação |
Erros
A API retorna estes códigos de status de erro:
- 400
Entrada malformada: um parâmetro incorreto, uma atualização em lote vazia ou com mais de 100 itens, ou uma escrita que define e limpa o mesmo campo na mesma chamada.
- 401
Sem chave, ou uma que não pode ser interpretada. Envie-a no cabeçalho X-API-Key ou como token bearer.
- 402
Uma cota do plano está no caminho — hoje, isso só acontece na criação de categorias.
- 403
A chave não carrega o escopo que essa chamada precisa — ou, em qualquer uma das duas escritas de transações, o id pertence a outra pessoa ou não existe. A API não distingue esses dois casos.
- 409
Outra coisa mudou a linha enquanto você escrevia. Leia-a de novo e envie sua escrita de novo.
Formatos de erro
Todo erro volta na mesma forma: statusCode, message e um objeto errors que nomeia o que deu errado. Uma chave ausente ou inválida pode voltar sem corpo nenhum.
Exemplo
{
"statusCode": 403,
"message": "One or more errors occurred!",
"errors": {
"generalErrors": ["Transaction does not belong to the authenticated user"]
}
}
ID da solicitação
Toda resposta carrega um cabeçalho fly-request-id. Inclua-o ao entrar em contato com o suporte sobre uma solicitação específica.
cURL
# Print the response headers, including fly-request-id; discard the body
curl -sS -D - -o /dev/null "https://forge.era.app/api/banking/transactions?page=1&pageSize=20" \
-H "X-API-Key: fmk_your_key_here"
cURL (escrita)
# A write call: same header, plus a JSON body
curl -sS -D - -X PUT "https://forge.era.app/api/banking/transactions/utgr_your_transaction_id" \
-H "X-API-Key: fmk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"categoryKey": "fcat_dining", "merchantName": "Corner Cafe"}'
Erros comuns
Definir um campo e limpá-lo na mesma escrita — 400.
Mais de 100 ids em uma atualização em lote — 400, e nada é alterado. Menos de um é igual.
Uma transação que não é sua, ou que não existe — 403, nunca 404. Então a resposta nunca diz se um id existe, só que não é seu para ver.
Outra coisa mudou a linha primeiro — 409.
Limites
Dois dos dez endpoints documentados limitam quanto você pode pedir em uma única chamada. Os outros oito não.
Isso não significa ilimitado: as chaves continuam expirando, as escritas continuam com limites de tamanho de campo, e seu plano ainda pode ocultar histórico antigo. Nada disso é um limite de taxa — veja abaixo.
Contas, saldo, resumo, categorias, tags e a escrita de uma única transação não têm limite de volume por chamada. Você recebe o conjunto inteiro de volta, ou a única linha que você nomeou.
pageSize é limitado a 100, não recusado. Peça mais e você recebe 100 linhas de volta com um 200 — leia pagination.pageSize na resposta em vez de confiar no que você enviou.
A escrita em lote de transações é limitada a 100 ids, e diferente de pageSize ela é recusada em vez de limitada: envie 101 e você recebe um 400, e nada muda.
As chaves expiram conforme o prazo que você escolhe na criação — até 90 dias no plano gratuito, 365 em um pago. Não existe opção que nunca expira.
Seu plano pode aplicar um piso de janela de histórico que esconde transações mais antigas. A resposta de transações carrega os campos historyWindow que dizem se um piso se aplicou e onde ele caiu.
Os planos também indicam uma cota de solicitações de API — 500 no plano gratuito, mais em cada plano pago.
O que não existe: não há limitação por solicitação no REST hoje, nem 429, nem cabeçalhos de limite de taxa — então uma chave vazada não é desacelerada por nada do nosso lado. Se você tiver dúvida sobre uma chave, revogue-a: isso a corta na hora (veja Segurança e gerenciamento de chaves acima). E, como essa API está em beta, não assuma que isso vai continuar assim.
Convenções
Os campos de resposta são camelCase. Os parâmetros de consulta não diferenciam maiúsculas de minúsculas, então camelCase funciona ali também — a especificação publicada escreve em PascalCase, e é por isso que você vê as duas formas por aí.
Um campo que nomeia um dia do calendário vem em YYYY-MM-DD. Um campo que nomeia um instante vem em ISO 8601 com o deslocamento de fuso.
Os tamanhos de página são limitados, não recusados. Peça um pageSize de 500 e você recebe 100 linhas e um 200, não um erro — então leia pagination.pageSize de volta em vez de confiar no que você mandou.
Uma resposta pode carregar campos que esta página não lista. Ignore os que você não reconhece em vez de falhar por causa deles — é isso que mantém o seu cliente funcionando conforme a API cresce.
REST é HTTP puro, então não precisa de SDK nenhum para chamar: qualquer linguagem com um cliente HTTP já serve. Não há nada para instalar.
Segurança e gestão de chaves
Aprovar um agente cria uma chave
Quando você aprova um agente por OAuth, a Era cria uma chave de API para ele. Ela aparece na mesma lista do painel que as suas, com um nome que a Era monta a partir do nome do próprio cliente.
Como ela se chama
Auto -- ClaudeEla carrega exatamente os escopos que você aprovou naquela tela, e nada além. Revogue pelo painel e o agente para de alcançar sua conta até você aprová-lo de novo.
Chamadas REST simples não são registradas
Criar e revogar uma chave aparecem no seu registro de atividade, assim como cada chamada de ferramenta que um agente faz por MCP. Chamadas REST individuais não: seja leitura ou escrita, hoje não existe registro requisição por requisição nesse caminho.
Se você ficar em dúvida sobre uma chave, revogue. A revogação é imediata, corta a chave tanto no REST quanto no MCP, e criar outra custa um minuto.
| Fato | O que significa |
|---|---|
| Os escopos são amplos | banking:read cobre muito mais do que as seis leituras desta página — o mesmo escopo cobre também o resto das leituras da sua conta: saldos, posições, conexões, gastos. Um escopo só, não existe opção mais estreita. Os de escrita também estão no cardápio, assim como os de leitura — então trate qualquer chave como uma senha. Ela age como a sua conta inteira, não como uma parte dela. banking:write pode mudar categorias, tags e metadados de transações, gerenciar contas e saldos manuais, e conectar ou desconectar instituições — nenhum escopo desta página pode mover dinheiro entre as suas contas bancárias. |
| Os escopos não são atualizados | Os escopos de uma chave ficam fixos quando ela é criada e nunca mudam depois. Isso importa para tudo o que um escopo cobre e ainda não está disponível: conceda social:write hoje e a chave ainda vai tê-lo quando as visualizações compartilhadas chegarem. Conceda o que você usa agora, não o que talvez use depois. |
| Não precisa de aprovação | Você já está logado na sua própria conta, então criar uma chave não precisa da aprovação de mais ninguém — não há revisão nem lista de espera, e ninguém na Era aprova o pedido. Fica escrito no seu registro de atividade assim que você a cria, então uma chave que você não reconhece é fácil de notar. |
| O acesso ao banco fica fora de alcance | Uma chave não alcança o acesso ao seu banco, porque a Era nunca o tem. Você digita no fluxo de conexão que o provedor de dados executa, não numa tela da Era — o que a Era guarda depois é um token de acesso por conexão, criptografado em repouso com AES-256, que você pode jogar fora desconectando a instituição. |
| As chaves são hasheadas, não armazenadas | Sua chave são 256 bits de dados aleatórios, com hash SHA-256 antes de ser armazenada. Guardamos o hash, não a chave. Se perder, revogue e crie outra. |
Recursos principais
Contas
Escopo necessário
banking:readTodas as contas que você consegue ver, em cada instituição conectada, com a contagem das que ficaram de fora ao lado delas. Cada conta carrega o seu accountGroupKey — o valor que o endpoint de saldo recebe no caminho — e o connectionId ao qual ela pertence, então esta é a primeira chamada a fazer. Aceita connectionId para restringir a uma única conexão, e includeExcluded para trazer as contas que você escondeu.
connectionIdopcional | Restringe a lista às contas de uma única conexão. |
|---|---|
includeExcludedopcional | Inclui também as contas excluídas por nível e as ocultas, com os saldos ofuscados. O padrão é false. |
Resposta · 200
{
"accounts": [
{
"accountGroupKey": "uagr_7f3c9a21",
"connectionId": "ucon_4b19e02c",
"name": "Everyday Checking",
"currentBalance": 4820.16,
"supportsTransactions": true,
…
}
],
"excludedAccountCount": 1
}
Em uma conta que você escondeu ou que o seu plano exclui, os campos de saldo voltam como null, não como zero — null quer dizer retido, não vazio. supportsTransactions vem null no mesmo espírito: quer dizer que a Era não tem como afirmar, nunca que a resposta é não.
Saldo de uma conta
Escopo necessário
banking:readO saldo de uma conta só, com os campos de crédito preenchidos quando a conta é um passivo. O caminho recebe o accountGroupKey dessa conta — o mesmo valor que /banking/accounts devolve para ela. Uma chave em outro formato é recusada antes mesmo de a busca rodar.
Resposta · 200
{
"accountGroupKey": "uagr_7f3c9a21",
"currentBalance": 4820.16,
"availableBalance": 4712.03,
"creditLimit": null,
"currencyCode": "USD",
"availableCredit": null,
"asOf": "2026-08-11T09:32:00Z",
"visibility": null
}
Uma conta escondida, ou uma cuja conexão foi cortada, ainda responde 200 — com os campos de saldo em null. Só uma conta que realmente não existe devolve 404. Repare aqui no campo visibility: ele é null quando a conta está visível, e uma string como tier_excluded quando não está.
Resumo das contas
Escopo necessário
banking:readOs totais das contas que você consegue ver: totalAssets, totalLiabilities e netWorthHint, que é o primeiro menos o segundo. Não aceita parâmetros.
Resposta · 200
{
"userId": "7d1c0b93a8e24f60",
"accounts": [ … ],
"totalVisibleCount": 6,
"totalHiddenCount": 2,
"totalAssets": 48210.75,
"totalLiabilities": 9327.40,
"netWorthHint": 38883.35,
"computedAt": "2026-08-11T09:32:00Z"
}
netWorthHint conta só as contas desta resposta, então totalHiddenCount diz o que está faltando. Trate como um número de partida, não como o seu patrimônio líquido definitivo.
Transações
Escopo necessário
banking:readSuas transações, uma página por vez, embrulhadas junto com as contagens de paginação. Aceita page e pageSize (100 é o teto), além de filtros opcionais por conta, período, regras aplicadas e etiquetas atribuídas.
accountIdopcional | Restringe às transações de uma conta, pelo seu accountGroupKey. |
|---|---|
fromDateopcional | Só transações nesta data ou depois. |
toDateopcional | Só transações nesta data ou antes. |
pageopcional | Número da página, começando em 1. O padrão é 1. |
pageSizeopcional | Linhas por página. O padrão é 50, limitado a 100. |
sortByopcional | Campo para ordenar: transactionDate, amount, description, category ou merchantName. |
sortDirectionopcional | asc ou desc. O padrão é decrescente. |
categoryKeyopcional | Só transações de uma categoria, pela sua chave fcat_. |
searchopcional | Busca de texto completo em comerciante, descrição, categoria, nome da conta e valor. |
ruleIdsopcional | Só transações que uma regra de automação tocou, pela chave da regra. |
tagKeysopcional | Só transações que carregam uma dessas etiquetas. |
reviewStatusopcional | needs_review, reviewed ou flagged. |
includeChildrenopcional | Com categoryKey definido, inclui também suas subcategorias. O padrão é false. |
Resposta · 200
{
"transactions": [ … ],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 412,
"totalPages": 21
},
"historyWindowApplied": true,
"historyWindowFloorDate": "2026-06-28",
"historyWindowHiddenCount": 137,
"historyWindowEarliestDate": "2024-03-02",
"historyWindowDegraded": false
}
Seu plano pode aplicar um corte de janela de histórico, que esconde as transações mais antigas que ele. É por isso que a resposta traz os campos historyWindow: historyWindowApplied diz que o corte realmente escondeu algo, historyWindowFloorDate é onde ele caiu, historyWindowHiddenCount é quantas linhas ficaram atrás, e historyWindowEarliestDate é até onde o seu histórico vai de verdade. Sem eles, um resultado curto é indistinguível de uma conta sem transações mais antigas. Dois deles mudam o que você escreve: historyWindowHiddenCount pode vir como null mesmo quando um corte foi aplicado, então leia null como desconhecido, não como zero; e quando historyWindowDegraded é true, a Era não conseguiu confirmar seu plano naquela leitura, então a data do corte é um palpite, não um fato. Numa leitura paga confirmada, nenhum corte é aplicado e historyWindowApplied volta como false.
Os planos também declaram uma cota de requisições de API — 500 no gratuito, e mais em cada plano pago. Os números atuais ficam listados junto com o resto dos limites do seu plano.
Mudar uma transação
Quatro coisas em uma transação são suas para substituir: a categoria, o nome do comerciante, uma nota sua e o status de revisão. Mande só as que você está mudando — o que você deixar de fora permanece como está. O id no caminho é a chave utgr_ da transação. Modifica dados, então precisa de banking:write em vez de banking:read.
Escopo necessário
banking:writecategoryKeyopcional | A chave fcat_ da categoria a atribuir. Deixe de fora e a transação mantém a categoria que já tem. |
|---|---|
merchantNameopcional | Um nome de comerciante seu, com até 1000 caracteres. Deixe de fora e o nome atual permanece. |
descriptionopcional | Uma nota sua sobre esta transação, com até 5000 caracteres. Deixe de fora e a nota atual permanece. |
reviewStatusopcional | Marque como needs_review, reviewed ou flagged. |
clearCategoryopcional | Descarta a sua substituição de categoria, para que a categorização da própria Era volte a valer. O padrão é false. |
clearMerchantNameopcional | Descarta a sua substituição de nome do comerciante, para que o nome que o seu banco mandou volte. O padrão é false. |
clearDescriptionopcional | Descarta a sua substituição de descrição, para que a descrição que o seu banco mandou volte. O padrão é false. |
clearReviewStatusopcional | Descarta a sua substituição de status de revisão. O padrão é false. |
Resposta · 200
{
"transaction": { … }
}
Você recebe de volta a transação inteira atualizada, no mesmo formato que a lista acima devolve — não reproduzido aqui, porque é um objeto grande que ainda está mudando. Definir um campo e limpá-lo na mesma chamada volta como 400. Uma transação que não é sua, ou que não existe, volta como 403 — a API não distingue os dois casos. E se outra coisa mudou a mesma linha enquanto você escrevia, você recebe 409: leia de novo e mande de novo.
Mudar até 100 de uma vez
As mesmas quatro substituições, aplicadas a uma lista de transações em uma única chamada. Todo id da lista recebe as mesmas mudanças — não há variação por transação. Modifica dados, então precisa de banking:write em vez de banking:read.
Escopo necessário
banking:writetransactionIds | As chaves utgr_ das transações a mudar. Pelo menos uma, e no máximo 100. Acima de 100 é recusado, não cortado — diferente do pageSize acima, você recebe um 400 e nada muda. |
|---|---|
categoryKeyopcional | A chave fcat_ da categoria a atribuir. Deixe de fora e a transação mantém a categoria que já tem. |
merchantNameopcional | Um nome de comerciante seu, com até 1000 caracteres. Deixe de fora e o nome atual permanece. |
descriptionopcional | Uma nota sua sobre esta transação, com até 5000 caracteres. Deixe de fora e a nota atual permanece. |
reviewStatusopcional | Marque como needs_review, reviewed ou flagged. |
clearCategoryopcional | Descarta a sua substituição de categoria, para que a categorização da própria Era volte a valer. O padrão é false. |
clearMerchantNameopcional | Descarta a sua substituição de nome do comerciante, para que o nome que o seu banco mandou volte. O padrão é false. |
clearDescriptionopcional | Descarta a sua substituição de descrição, para que a descrição que o seu banco mandou volte. O padrão é false. |
clearReviewStatusopcional | Descarta a sua substituição de status de revisão. O padrão é false. |
Resposta · 200
{
"transactions": [ … ]
}
Você recebe de volta as transações atualizadas, no mesmo formato que a lista acima devolve. Definir um campo e limpá-lo na mesma chamada volta como 400, e uma lista vazia também. Uma lista que contenha uma transação que não é sua, ou que não existe, volta como 403 para a chamada inteira — nada é alterado. Se outra coisa mudou uma dessas linhas enquanto você escrevia, você recebe 409: leia de novo e mande de novo.
Categorias
Escopo necessário
banking:readToda a taxonomia de categorias: cada conjunto de categorias, com as subcategorias aninhadas dentro. A taxonomia é compartilhada, não por conta.
Resposta · 200
{
"packs": [
{
"packSlug": "default",
"packName": "Era default categories",
"isDefault": true,
"categories": [
{
"projectionKey": "fcat_food_dining",
"categoryName": "Food & dining",
"isTopLevel": true,
"children": [ … ]
}
]
}
],
"meterLimit": 25,
"canCreateCustomCategories": true
}
Adicionar uma categoria
Uma categoria definida pelo usuário sob um pai existente. Modifica dados, então precisa de banking:write em vez de banking:read.
Escopo necessário
banking:writeslug | Identificador compatível com URL — letras minúsculas, números e hifens, de 2 a 50 caracteres. |
|---|---|
parentCategoryKey | A chave fcat_ da categoria sob a qual esta se aninha. |
name | Nome de exibição. |
descriptionopcional | Descrição opcional. |
iconNameopcional | Nome de ícone opcional. |
spendingTypeopcional | Classificação de gasto opcional. |
displayOrderopcional | Posição de ordenação opcional entre as categorias irmãs. |
assignmentEligibilityopcional | Regra opcional sobre a quais transações esta categoria pode ser atribuída. |
sourceSystemKeysopcional | Lista opcional de chaves de categorias existentes cujas transações devem ser roteadas para cá daqui em diante. |
applyRetroactivelyopcional | Quando true, reavalia também as transações passadas conforme o novo roteamento. O padrão é false. |
Resposta · 201
{
"categoryKey": "fcat_side_hustle_9f2a",
"overlayProjectionKey": "fcov_9f2a1c",
"action": "created",
"isQuotaExceeded": false,
"createdMappingRuleKeys": [ … ],
…
}
A resposta também traz retroactiveAffectedCount, mergeSourcesHiddenCount, mergeSourcesTotalCount e meterGate — campos que essa chamada compartilha com fusões de categorias e criações limitadas por cota, não mostrados aqui.