Avvio rapido
Prima di iniziare ti serve un account Era con almeno un istituto collegato: senza una connessione questi endpoint non hanno niente da restituire.
- 1
Accedi a Era e collega un istituto, se non l'hai già fatto.
- 2
Apri le tue chiavi API nella dashboard e creane una. All'inizio sono spuntati tutti gli scope, quindi togli la spunta a quelli che non ti servono — per questi endpoint resta banking:read. Scegli anche una scadenza; non esiste un'opzione senza scadenza.
- 3
Copia la chiave. Viene mostrata una volta sola e non possiamo mostrartela di nuovo. Copiala e conservala in un posto sicuro, come un gestore di segreti. Se perdi una chiave, non puoi più vederla. Creane una nuova al suo posto.
- 4
Mandala in un header insieme alla tua richiesta.
cURL
curl "https://forge.era.app/api/banking/transactions?page=1&pageSize=20" \
-H "X-API-Key: fmk_your_key_here"
Risposta · 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
}
API disponibili
L'API di Era include le seguenti API:
- GET/banking/accounts
Ogni account che puoi vedere, su tutte le istituzioni collegate.
- GET/banking/accounts/{accountId}/balance
Il saldo di un account, con i campi di credito compilati se è una passività.
- GET/banking/accounts/summary
I totali su tutti gli account che puoi vedere.
- GET/banking/transactions
Le tue transazioni, una pagina alla volta.
- PUT/banking/transactions/{id}
Modifica una transazione
- PUT/banking/transactions/bulk
Modifica fino a 100 alla volta
- GET/banking/categories
L'intera tassonomia delle categorie, con le sottocategorie annidate.
- POST/banking/categories
Aggiungi una categoria
- GET/banking/tags
Tutti i tag del tuo account, in un'unica risposta.
- POST/banking/tags
Crea un tag
Autenticazione
Invia la tua chiave in uno di questi due modi:
| Metodo | Credenziale |
|---|---|
| Header | X-API-Key: fmk_your_key_here |
| Token bearer | Authorization: Bearer fmk_your_key_here |
Ogni richiesta è cifrata con TLS.
Le chiavi scadono, e quando ne crei una scegli tu tra quanto. La durata massima disponibile è di 90 giorni sul piano gratuito e di 365 su uno a pagamento: non esiste un'opzione senza scadenza, quindi qualsiasi cosa tu costruisca su questo ha bisogno di un piano per ruotare la chiave prima che scada.
Header di risposta
Ogni risposta include:
| Header | Descrizione |
|---|---|
| fly-request-id | Un identificativo univoco della richiesta. Includilo quando contatti il supporto per una richiesta specifica — vedi ID richiesta |
Errori
L'API restituisce questi codici di stato di errore:
- 400
Input malformato: un parametro sbagliato, un aggiornamento massivo vuoto o con più di 100 elementi, o una scrittura che imposta e cancella lo stesso campo nella stessa chiamata.
- 401
Nessuna chiave, o una che non si può interpretare. Inviala nell'intestazione X-API-Key o come token bearer.
- 402
Una quota del piano è d'intralcio — oggi succede solo con la creazione di categorie.
- 403
La chiave non porta lo scope di cui questa chiamata ha bisogno — oppure, su una delle due scritture di transazioni, l'id appartiene a qualcun altro o non esiste affatto. L'API non distingue i due casi.
- 409
Qualcos'altro ha cambiato la riga mentre stavi scrivendo. Rileggila e reinvia la tua scrittura.
Forme di errore
Ogni errore torna nella stessa forma: statusCode, message e un oggetto errors che indica cosa non andava. Una chiave mancante o non valida può tornare senza alcun corpo.
Esempio
{
"statusCode": 403,
"message": "One or more errors occurred!",
"errors": {
"generalErrors": ["Transaction does not belong to the authenticated user"]
}
}
ID richiesta
Ogni risposta porta un'intestazione fly-request-id. Includila quando contatti il supporto per una richiesta specifica.
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 (scrittura)
# 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"}'
Errori comuni
Impostare un campo e cancellarlo nella stessa scrittura — 400.
Più di 100 id in un aggiornamento massivo — 400, e non cambia nulla. Meno di uno è lo stesso.
Una transazione che non è tua, o che non esiste — 403, mai 404. Quindi la risposta non ti dice mai se un id esiste, solo che non è tuo da vedere.
Qualcos'altro ha cambiato la riga per primo — 409.
Limiti
Due dei dieci endpoint documentati limitano quanto puoi chiedere in una singola chiamata. Gli altri otto no.
Questo non significa illimitato: le chiavi continuano a scadere, le scritture hanno comunque limiti di lunghezza dei campi, e il tuo piano può comunque nascondere lo storico più vecchio. Niente di tutto questo è un rate limit — vedi sotto.
Account, saldo, riepilogo, categorie, tag e la scrittura di una singola transazione non hanno alcun limite di volume per chiamata. Ricevi l'intero insieme, oppure la singola riga che hai indicato.
pageSize è limitato a 100, non rifiutato. Chiedine di più e ricevi 100 righe con un 200 — leggi pagination.pageSize nella risposta invece di fidarti di ciò che hai inviato.
La scrittura massiva delle transazioni è limitata a 100 id, e a differenza di pageSize viene rifiutata anziché limitata: invia 101 e ricevi un 400, senza che nulla cambi.
Le chiavi scadono secondo il programma che scegli alla creazione — fino a 90 giorni nel piano gratuito, 365 in uno a pagamento. Non esiste un'opzione senza scadenza.
Il tuo piano può applicare un limite di finestra della cronologia che nasconde le transazioni più vecchie. La risposta delle transazioni porta i campi historyWindow che dicono se un limite si è applicato e dove è caduto.
I piani indicano anche un'assegnazione di richieste API — 500 nel piano gratuito, di più in ogni piano a pagamento.
Cosa manca: oggi su REST non c'è nessuna limitazione per richiesta, nessun 429, e nessuna intestazione di limite di frequenza — quindi una chiave trapelata non viene rallentata da nulla dal nostro lato. Se hai mai un dubbio su una chiave, revocala: la disattiva subito (vedi Sicurezza e gestione della chiave più sopra). E, dato che questa API è in beta, non dare per scontato che rimanga così.
Convenzioni
I campi delle risposte sono in camelCase. I parametri di query non distinguono maiuscole e minuscole, quindi lì funziona anche il camelCase: la specifica pubblicata li scrive in PascalCase, ed è per questo che in giro vedi entrambe le forme.
Un campo che indica un giorno di calendario è in formato YYYY-MM-DD. Un campo che indica un istante è in ISO 8601 con l'offset.
Le dimensioni delle pagine vengono limitate, non rifiutate. Chiedi un pageSize di 500 e ottieni 100 righe e un 200, non un errore: leggi quindi pagination.pageSize invece di fidarti di quello che hai mandato.
Una risposta può portare campi che questa pagina non elenca. Ignora quelli che non riconosci invece di fallire: è questo che tiene in piedi il tuo client mentre l'API cresce.
REST è semplice HTTP, quindi per chiamarlo non serve nessun SDK: va bene qualsiasi linguaggio con un client HTTP. Non c'è niente da installare.
Sicurezza e gestione delle chiavi
Approvare un agente crea una chiave
Quando approvi un agente tramite OAuth, Era crea una chiave API per lui. Finisce nella stessa lista della dashboard delle chiavi che crei tu, con un nome che Era genera dal nome del client stesso.
Come viene chiamata
Auto -- ClaudePorta esattamente gli scope che hai approvato su quella schermata, e nient'altro. Revocala dalla dashboard e l'agente smette di raggiungere il tuo account finché non lo approvi di nuovo.
Le semplici chiamate REST non vengono registrate
La creazione e la revoca di una chiave compaiono entrambe nel tuo registro attività, e lo stesso vale per ogni chiamata a uno strumento che un agente fa tramite MCP. Le singole chiamate REST no: lettura o scrittura che sia, oggi su quel percorso non c'è un log per singola richiesta.
Se hai un dubbio su una chiave, revocala. La revoca è immediata, taglia fuori la chiave sia su REST sia su MCP, e crearne un'altra richiede un minuto.
| Fatto | Cosa significa |
|---|---|
| Gli scope sono grossolani | banking:read copre molto più delle sei letture di questa pagina — lo stesso scope copre anche il resto delle letture del tuo account: saldi, partecipazioni, connessioni, spese. Un unico scope, non esiste un'opzione più stretta. Anche gli scope di scrittura sono nel menu, come quelli di lettura — quindi tratta qualsiasi chiave come una password. Agisce come il tuo account, non come una sua parte. banking:write può modificare categorie, tag e metadati delle transazioni, gestire conti e saldi manuali e collegare o scollegare istituti — nessuno scope di questa pagina può spostare denaro tra i tuoi conti bancari. |
| Gli scope non si aggiornano | Gli scope di una chiave si fissano nel momento in cui la crei e non cambiano più. Questo conta per tutto ciò che uno scope copre ma che non è ancora attivo: concedi social:write oggi e la chiave ce l'ha ancora quando arrivano le viste condivise. Concedi quello che stai usando adesso, non quello che potresti usare più avanti. |
| Nessuna approvazione richiesta | Hai già effettuato l'accesso al tuo account, quindi creare una chiave non richiede l'approvazione di nessun altro: non c'è nessuna revisione e nessuna lista d'attesa, e nessuno in Era approva la richiesta. Viene scritta nel tuo registro attività non appena la crei, quindi una chiave che non riconosci è facile da individuare. |
| Le credenziali della banca restano fuori portata | Una chiave non può arrivare alle credenziali della tua banca, perché Era non le ha mai. Le inserisci nel flusso di connessione gestito dal fornitore di dati, non in una schermata di Era: quello che Era conserva dopo è un token di accesso per singola connessione, cifrato a riposo con AES-256, che puoi buttare via scollegando l'istituto. |
| Le chiavi vengono sottoposte a hash, non memorizzate | La tua chiave è fatta di 256 bit di dati casuali, sottoposti a hash SHA-256 prima di essere memorizzati. Conserviamo l'hash, non la chiave. Se la perdi, revocala e creane un'altra. |
Risorse principali
Conti
Scope necessario
banking:readTutti i conti che riesci a vedere, su ogni istituto collegato, con accanto il conteggio di quelli rimasti fuori. Ogni conto porta con sé il suo accountGroupKey — il valore che l'endpoint del saldo accetta nel percorso — e il connectionId a cui appartiene, quindi è da questa chiamata che si parte. Accetta connectionId per restringere a una sola connessione e includeExcluded per far rientrare i conti che hai nascosto.
connectionIdfacoltativo | Restringe l'elenco ai conti di una sola connessione. |
|---|---|
includeExcludedfacoltativo | Include anche i conti esclusi per livello e quelli nascosti, con i saldi offuscati. Il default è false. |
Risposta · 200
{
"accounts": [
{
"accountGroupKey": "uagr_7f3c9a21",
"connectionId": "ucon_4b19e02c",
"name": "Everyday Checking",
"currentBalance": 4820.16,
"supportsTransactions": true,
…
}
],
"excludedAccountCount": 1
}
Su un conto che hai nascosto o che il tuo piano esclude, i campi del saldo tornano null e non zero: null vuol dire trattenuto, non vuoto. supportsTransactions è null nello stesso spirito: vuol dire che Era non può dirlo, mai che la risposta sia no.
Saldo di un conto
Scope necessario
banking:readIl saldo di un singolo conto, con i campi del credito compilati quando il conto è una passività. Il percorso accetta l'accountGroupKey del conto — lo stesso valore che /banking/accounts restituisce per quel conto. Una chiave di un'altra forma viene rifiutata prima ancora che parta la ricerca.
Risposta · 200
{
"accountGroupKey": "uagr_7f3c9a21",
"currentBalance": 4820.16,
"availableBalance": 4712.03,
"creditLimit": null,
"currencyCode": "USD",
"availableCredit": null,
"asOf": "2026-08-11T09:32:00Z",
"visibility": null
}
Un conto nascosto, o uno la cui connessione è stata interrotta, risponde comunque 200 — con i campi del saldo a null. Solo un conto che davvero non c'è ti dà un 404. Qui tieni d'occhio il campo visibility: è null quando il conto è visibile, ed è una stringa come tier_excluded quando non lo è.
Riepilogo dei conti
Scope necessario
banking:readI totali sui conti che riesci a vedere: totalAssets, totalLiabilities e netWorthHint, che è il primo meno il secondo. Non accetta parametri.
Risposta · 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 solo i conti presenti in questa risposta, quindi è totalHiddenCount a dirti cosa gli manca. Trattalo come una cifra di partenza, non come un patrimonio netto definitivo.
Transazioni
Scope necessario
banking:readLe tue transazioni, una pagina alla volta, avvolte in un contenitore che porta accanto i conteggi di paginazione. Accetta page e pageSize (100 è il massimo), più filtri opzionali per conto, intervallo di date, regole applicate e tag assegnati.
accountIdfacoltativo | Restringe alle transazioni di un conto, tramite il suo accountGroupKey. |
|---|---|
fromDatefacoltativo | Solo transazioni da questa data in poi. |
toDatefacoltativo | Solo transazioni fino a questa data. |
pagefacoltativo | Numero di pagina, a partire da 1. Il default è 1. |
pageSizefacoltativo | Righe per pagina. Il default è 50, limitato a 100. |
sortByfacoltativo | Campo per l'ordinamento: transactionDate, amount, description, category o merchantName. |
sortDirectionfacoltativo | asc o desc. Il default è decrescente. |
categoryKeyfacoltativo | Solo transazioni di una categoria, tramite la sua chiave fcat_. |
searchfacoltativo | Ricerca full-text su commerciante, descrizione, categoria, nome del conto e importo. |
ruleIdsfacoltativo | Solo transazioni toccate da una regola di automazione, tramite la chiave della regola. |
tagKeysfacoltativo | Solo transazioni che portano uno di questi tag. |
reviewStatusfacoltativo | needs_review, reviewed o flagged. |
includeChildrenfacoltativo | Con categoryKey impostato, include anche le sue sottocategorie. Il default è false. |
Risposta · 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
}
Il tuo piano può applicare un limite alla finestra di cronologia, che nasconde le transazioni più vecchie di quella soglia. È per questo che la risposta porta con sé i campi historyWindow: historyWindowApplied ti dice che un limite ha davvero nascosto qualcosa, historyWindowFloorDate è dove è caduto, historyWindowHiddenCount è quante righe ci sono dietro e historyWindowEarliestDate è fin dove arriva davvero la tua cronologia. Senza di loro un risultato corto è indistinguibile da un conto senza transazioni più vecchie. Due di questi cambiano il codice che scrivi: historyWindowHiddenCount può essere null anche quando un limite è stato applicato, quindi leggi null come sconosciuto e non come zero; e quando historyWindowDegraded è true, su quella lettura Era non è riuscita a confermare il tuo piano, quindi la data del limite è una stima e non un dato certo. Su una lettura a pagamento con il piano confermato non si applica nessun limite e historyWindowApplied torna false.
I piani indicano anche un massimale di richieste API: 500 sul piano gratuito, di più su ognuno di quelli a pagamento. I numeri attuali sono elencati insieme al resto dei limiti del tuo piano.
Modifica una transazione
Su una transazione puoi sovrascrivere quattro cose: la sua categoria, il nome del commerciante, una nota tua e il suo stato di revisione. Manda solo quelle che stai cambiando — tutto ciò che ometti resta com'è. L'id nel percorso è la chiave utgr_ della transazione. Modifica dati, quindi serve banking:write invece di banking:read.
Scope necessario
banking:writecategoryKeyfacoltativo | La chiave fcat_ della categoria da assegnare. Ometti il campo e la transazione conserva la categoria che ha. |
|---|---|
merchantNamefacoltativo | Un nome del commerciante scelto da te, fino a 1000 caratteri. Ometti il campo e il nome attuale resta invariato. |
descriptionfacoltativo | Una nota tua su questa transazione, fino a 5000 caratteri. Ometti il campo e la nota attuale resta invariata. |
reviewStatusfacoltativo | Impostalo su needs_review, reviewed o flagged. |
clearCategoryfacoltativo | Rimuove la tua sovrascrittura della categoria, così torna a valere la categorizzazione di Era. Il default è false. |
clearMerchantNamefacoltativo | Rimuove la tua sovrascrittura del nome del commerciante, così torna il nome che ha mandato la tua banca. Il default è false. |
clearDescriptionfacoltativo | Rimuove la tua sovrascrittura della descrizione, così torna la descrizione che ha mandato la tua banca. Il default è false. |
clearReviewStatusfacoltativo | Rimuove la tua sovrascrittura dello stato di revisione. Il default è false. |
Risposta · 200
{
"transaction": { … }
}
Ricevi indietro l'intera transazione aggiornata, nella stessa forma restituita dall'elenco qui sopra — non ripetuta qui, perché è un oggetto grande e ancora in evoluzione. Impostare un campo e cancellarlo nella stessa chiamata dà 400. Una transazione che non è tua, o che non esiste affatto, dà 403 — l'API non distingue i due casi. E se qualcos'altro ha modificato la stessa riga mentre stavi scrivendo, ricevi 409: rileggila e rimandala.
Modifica fino a 100 alla volta
Le stesse quattro sovrascritture, applicate a un elenco di transazioni in un'unica chiamata. Ogni id nell'elenco riceve le stesse modifiche — non c'è variazione per singola transazione. Modifica dati, quindi serve banking:write invece di banking:read.
Scope necessario
banking:writetransactionIds | Le chiavi utgr_ delle transazioni da modificare. Almeno una, e non più di 100. Oltre 100 viene rifiutato invece che troncato — a differenza di pageSize qui sopra, ricevi un 400 e non cambia nulla. |
|---|---|
categoryKeyfacoltativo | La chiave fcat_ della categoria da assegnare. Ometti il campo e la transazione conserva la categoria che ha. |
merchantNamefacoltativo | Un nome del commerciante scelto da te, fino a 1000 caratteri. Ometti il campo e il nome attuale resta invariato. |
descriptionfacoltativo | Una nota tua su questa transazione, fino a 5000 caratteri. Ometti il campo e la nota attuale resta invariata. |
reviewStatusfacoltativo | Impostalo su needs_review, reviewed o flagged. |
clearCategoryfacoltativo | Rimuove la tua sovrascrittura della categoria, così torna a valere la categorizzazione di Era. Il default è false. |
clearMerchantNamefacoltativo | Rimuove la tua sovrascrittura del nome del commerciante, così torna il nome che ha mandato la tua banca. Il default è false. |
clearDescriptionfacoltativo | Rimuove la tua sovrascrittura della descrizione, così torna la descrizione che ha mandato la tua banca. Il default è false. |
clearReviewStatusfacoltativo | Rimuove la tua sovrascrittura dello stato di revisione. Il default è false. |
Risposta · 200
{
"transactions": [ … ]
}
Ricevi indietro le transazioni aggiornate, nella stessa forma restituita dall'elenco qui sopra. Impostare un campo e cancellarlo nella stessa chiamata dà 400, e lo stesso vale per un elenco vuoto. Un elenco che contiene una transazione che non è tua, o che non esiste affatto, dà 403 per l'intera chiamata — non viene modificato nulla. Se qualcos'altro ha modificato una di quelle righe mentre stavi scrivendo, ricevi 409: rileggile e rimandale.
Categorie
Scope necessario
banking:readL'intera tassonomia delle categorie: ogni insieme di categorie, con le sue sottocategorie annidate dentro. La tassonomia è condivisa, non è per singolo conto.
Risposta · 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
}
Aggiungi una categoria
Una categoria definita dall'utente sotto un genitore esistente. Modifica dati, quindi serve banking:write invece di banking:read.
Scope necessario
banking:writeslug | Identificatore adatto a un URL — lettere minuscole, numeri e trattini, da 2 a 50 caratteri. |
|---|---|
parentCategoryKey | La chiave fcat_ della categoria sotto cui questa viene annidata. |
name | Nome visualizzato. |
descriptionfacoltativo | Descrizione facoltativa. |
iconNamefacoltativo | Nome icona facoltativo. |
spendingTypefacoltativo | Classificazione di spesa facoltativa. |
displayOrderfacoltativo | Posizione d'ordine facoltativa tra le categorie sorelle. |
assignmentEligibilityfacoltativo | Regola facoltativa su quali transazioni può ricevere questa categoria. |
sourceSystemKeysfacoltativo | Elenco facoltativo di chiavi di categorie esistenti le cui transazioni dovranno essere instradate qui d'ora in poi. |
applyRetroactivelyfacoltativo | Se true, rivaluta anche le transazioni passate secondo il nuovo instradamento. Il default è false. |
Risposta · 201
{
"categoryKey": "fcat_side_hustle_9f2a",
"overlayProjectionKey": "fcov_9f2a1c",
"action": "created",
"isQuotaExceeded": false,
"createdMappingRuleKeys": [ … ],
…
}
La risposta porta anche retroactiveAffectedCount, mergeSourcesHiddenCount, mergeSourcesTotalCount e meterGate — campi che questa chiamata condivide con le fusioni di categorie e le creazioni limitate dalla quota, non mostrati qui.