Sviluppatori

Riferimento API v1

REST · JSON · OAuth 2.0 Bearer https://api.manilo.app Stabile — nessuna modifica incompatibile all’interno di v1

Panoramica

L’API di Manilo è un’API REST JSON per gestire in modo programmatico lo stesso registro che usi nell’app iOS: conti, categorie, budget, gruppi condivisi e transazioni. Usala per costruire importatori, esportatori, ponti di sincronizzazione, dashboard o per alimentare le tue automazioni.

  • URL di base: https://api.manilo.app — l’URL di base precedente api.ledgy.app continua a funzionare.
  • Prefisso di versione: tutti gli endpoint di questo documento sono esposti sotto /api/v1/.
  • Trasporto: solo HTTPS. Le richieste HTTP non vengono accettate.
  • Codifica: corpi di richiesta e risposta in JSON. UTF-8. Nomi delle proprietà in camelCase.
  • Autenticazione: Authorization: Bearer … a ogni richiesta.
  • Abbonamento Cloud: richiesto su ogni endpoint v1. Vedi Requisito di abbonamento.
Cerchi un assistente IA? Se vuoi che Claude, ChatGPT o Cursor parlino con Manilo per tuo conto, usa l’endpoint Model Context Protocol all’indirizzo https://api.manilo.app/mcp — vedi Integrazioni. L’API REST documentata qui è pensata per il codice che scrivi tu.

Avvio rapido

Tre passaggi per arrivare alla tua prima richiesta autenticata.

1. Genera un Personal Access Token

  1. Accedi alla tua dashboard Manilo e apri Impostazioni → Accesso API.
  2. Fai clic su + Nuovo token.
  3. Dai al token un nome descrittivo (ad es. “Zapier — esportazione settimanale”), scegli gli ambiti che ti servono (vedi Ambiti) e, se vuoi, imposta una scadenza.
  4. Copia il token. Viene mostrato una sola volta. I token iniziano con il prefisso lgpat_ seguito da 64 caratteri esadecimali.

La stessa pagina elenca i tuoi token attivi con la data dell’ultimo utilizzo e il numero di permessi, mostra un avviso “In scadenza tra 30 giorni” e ti permette di revocare qualsiasi token all’istante tramite l’icona del cestino. Ogni account può avere fino a 25 token attivi contemporaneamente.

2. Esegui una richiesta

cURLElenca i conti
# Replace lgpat_… with your token
curl "https://api.manilo.app/api/v1/accounts" \
  -H "Authorization: Bearer lgpat_a1b2c3d4e5…"

3. Esamina la risposta

200 OKapplication/json
{
  "items": [
    {
      "id": "acc_01HK8V…",
      "name": "Wise EUR",
      "currencyCode": "EUR",
      "initialBalance": 1240.50,
      "icon": "wallet",
      "color": "#4A90E2",
      "order": 0,
      "createdAt": "2026-04-12T08:13:09Z",
      "updatedAt": "2026-05-01T17:02:31Z"
    }
  ],
  "totalCount": 1
}
Tratta il tuo token come una password. Chiunque abbia il token può leggere o modificare il tuo registro entro gli ambiti che hai concesso. Revoca subito i token compromessi da Impostazioni → Accesso API.

Autenticazione

Ogni richiesta a /api/v1/ deve includere un’intestazione Authorization. Sono accettati due tipi di token:

  • Personal Access Token (PAT) — token bearer di lunga durata che crei dalla pagina Impostazioni → Accesso API della dashboard. Formato: lgpat_ + 64 caratteri esadecimali. Con ambiti, revocabile, con scadenza facoltativa. Consigliato per tutte le integrazioni di terze parti.
  • JWT di sessione — token di breve durata emesso per le app first-party (iOS, dashboard). Non ha restrizioni di ambito. Puoi usarlo per un test occasionale, se riesci a estrarne uno da una sessione autenticata, ma la strada supportata sono i PAT.

Formato dell’intestazione

HTTP
Authorization: Bearer lgpat_a1b2c3d4e5f6…

Limiti dei token

  • Fino a 25 PAT attivi per account Manilo.
  • Al momento della creazione si può impostare una scadenza facoltativa. I token scaduti restituiscono 401 Unauthorized.
  • I token revocati smettono di funzionare immediatamente: Manilo conserva solo un hash SHA-256 del token, mai il valore, quindi un token trapelato non può essere recuperato, ma solo revocato e sostituito.

Errori di autenticazione comuni

401
Token mancante, malformato, scaduto o revocato.
403
Il token è valido, ma l’endpoint richiesto esige un ambito che il tuo PAT non possiede, oppure il tuo abbonamento Cloud non è attivo.

Ambiti

I PAT seguono un modello deny-by-default (tutto negato salvo esplicita concessione). Un token può chiamare solo gli endpoint di cui possiede l’ambito richiesto; tutto il resto restituisce 403 Forbidden. Concedi l’insieme di ambiti più ristretto di cui la tua integrazione ha davvero bisogno.

Ambiti disponibili:

accounts:read accounts:write categories:read categories:write budgets:read budgets:write groups:read groups:write transactions:read transactions:write tags:read tags:write recurring:read recurring:write settings:read settings:write

Ogni endpoint elencato di seguito mostra l’ambito richiesto in una piccola etichetta viola. Gli ambiti :write non implicano quelli :read: richiedili entrambi se ti servono entrambi.

Requisito di abbonamento

Tutti gli endpoint v1 — comprese le operazioni di sola lettura — richiedono che l’utente chiamante abbia un abbonamento Manilo Cloud attivo. Se l’abbonamento è decaduto, è scaduto o non è mai stato attivato, l’API risponde con:

403 Forbidden
HTTP/1.1 403 Forbidden
X-Subscription-Required: true
Content-Type: application/json

{ "error": "Active cloud subscription required" }

L’intestazione X-Subscription-Required permette ai client di distinguere un blocco dovuto all’abbonamento da un generico rifiuto per permessi insufficienti. Per ripristinare l’accesso, riattiva Cloud nell’app iOS oppure su dashboard.manilo.app/upgrade.

Errori

Gli errori usano i codici di stato HTTP standard. Il corpo della risposta è un oggetto JSON con un solo campo:

JSON
{ "error": "Human-readable message" }

Codici di stato da gestire:

200
OK — risorsa restituita, oppure elenco restituito.
201
Created — nuova risorsa creata. L’intestazione Location punta all’URL canonico.
204
No Content — eliminazione riuscita; nessun corpo.
400
Convalida non riuscita — campo obbligatorio mancante, valore fuori intervallo, JSON malformato.
401
Autenticazione non riuscita — vedi Autenticazione.
403
Permesso negato — ambito insufficiente o abbonamento non attivo.
404
Risorsa non trovata, oppure nascosta da un controllo di autorizzazione.
409
Conflict — ad es. violazione di un vincolo di unicità.
5xx
Errore lato server. È sicuro riprovare le letture idempotenti con backoff esponenziale.

Paginazione e filtri

Per impostazione predefinita, gli endpoint di elenco restituiscono tutti gli elementi corrispondenti. Le transazioni, l’unica risorsa che può diventare voluminosa, supportano la paginazione a cursore.

Cursore delle transazioni

cURLElenco paginato
curl "https://api.manilo.app/api/v1/transactions?limit=50&type=expense&dateFrom=2026-01-01" \
  -H "Authorization: Bearer lgpat_…"

La risposta include un nextCursor. Rimandalo indietro come parametro di query cursor per ottenere la pagina successiva; quando nextCursor è null, sei arrivato alla fine.

  • limit — dimensione della pagina, limitata all’intervallo 1..200. Valore predefinito 50.
  • cursor — token opaco. Trattalo come una scatola nera.
  • type, dateFrom, dateTo, categoryId, accountId, groupId — filtri facoltativi; vedi l’endpoint Elenca transazioni.

Tipi e formati

  • ID — stringhe opache. Non analizzarle; trattale come identificatori UTF-8 sensibili a maiuscole e minuscole.
  • Timestamp — ISO-8601 in UTC con un carattere Z finale, ad es. "2026-05-13T10:30:00Z".
  • Date (ad es. il campo date di una transazione) — stesso formato ISO-8601, ma è significativa solo la parte della data.
  • Importi — numeri JSON espressi in unità principali con un massimo di 4 decimali (ad es. 12.50). Mai in unità secondarie. Sempre accompagnati da currencyCode.
  • Codici valuta — ISO-4217, esattamente tre lettere maiuscole (ad es. "EUR", "USD", "GBP").
  • Eliminazioni — tutte le operazioni di eliminazione sono eliminazioni logiche. Gli elementi eliminati smettono di comparire nelle risposte di elenco e di lettura; i partner di condivisione e gli scontrini storici vengono conservati.
  • Effetti collaterali — eliminare un conto, una categoria o un gruppo lascia intatte le transazioni collegate; i loro riferimenti vengono staccati. L’endpoint Elimina conto accetta una strategia esplicita.

Conti

I conti sono i contenitori che custodiscono i saldi: un conto bancario, una carta di credito, un portafoglio in contanti, un conto di investimento. Ogni transazione è collegata a un conto (o a due, nel caso dei trasferimenti).

GET /api/v1/accounts accounts:read

Restituisce tutti i conti di cui l’utente autenticato è proprietario o a cui ha accesso.

GET /api/v1/accounts/{id} accounts:read

Recupera un conto tramite id. 404 se non viene trovato.

POST /api/v1/accounts accounts:write

Crea un nuovo conto. Restituisce 201 con l’oggetto creato e un’intestazione Location.

Corpo della richiesta
CampoTipoDescrizione
namestringobbligatorioNome visualizzato. Massimo 100 caratteri.
currencyCodestringobbligatorioISO-4217. Esattamente 3 lettere.
initialBalancenumberobbligatorioSaldo iniziale in currencyCode.
orderintegerobbligatorioPosizione di ordinamento. I valori più bassi vengono prima.
iconstringfacoltativoIdentificatore dell’icona da /api/v1/icons. Massimo 50.
colorstringfacoltativoColore esadecimale, ad es. "#4A90E2". Massimo 20.
iconColorstringfacoltativoSovrascrive la tinta dell’icona.
Richiesta
POST /api/v1/accounts
{
  "name": "Cash",
  "currencyCode": "EUR",
  "initialBalance": 50.00,
  "order": 2,
  "icon": "wallet",
  "color": "#22C55E"
}
201 Created
{
  "id": "acc_01HK8V…",
  "name": "Cash",
  "currencyCode": "EUR",
  "initialBalance": 50.00,
  "order": 2,
  "icon": "wallet",
  "color": "#22C55E",
  "iconColor": null,
  "shareInviteToken": null,
  "createdAt": "2026-05-13T10:30:00Z",
  "updatedAt": "2026-05-13T10:30:00Z"
}
PUT /api/v1/accounts/{id} accounts:write

Sostituisce un conto esistente. Il corpo è identico a Crea; vanno forniti tutti i campi.

DELETE /api/v1/accounts/{id} accounts:write

Elimina logicamente un conto. Decidi cosa succede alle sue transazioni tramite il parametro di query action.

Parametri di query
CampoTipoDescrizione
actionenumfacoltativoDetach (predefinito): azzera il riferimento al conto su ogni transazione. Move: riassegna le transazioni a moveTargetAccountId. DeleteAll: elimina logicamente tutte le transazioni collegate di cui sei proprietario.
moveTargetAccountIdstringfacoltativoObbligatorio quando action=Move. Id del conto di destinazione.

Categorie

Le categorie indicano a cosa si riferisce una transazione (spesa alimentare, affitto, entrate da lavoro autonomo). Le categorie di sistema sono di sola lettura e condivise da tutti gli utenti; le categorie utente sono tue e le gestisci tu. I gruppi di categorie riuniscono categorie correlate.

GET /api/v1/categories/system-categories categories:read

Restituisce l’insieme curato di categorie “note” di Manilo: il set iniziale incluso nell’app iOS. Sono versionate a livello globale e si possono mettere in cache in sicurezza in base a version.

Categorie utente

GET /api/v1/categories categories:read

Elenca tutte le categorie definite dall’utente.

GET /api/v1/categories/{id} categories:read

Recupera una categoria utente tramite id.

POST /api/v1/categories categories:write

Crea una categoria utente.

Corpo della richiesta
CampoTipoDescrizione
namestringobbligatorioNome visualizzato. Massimo 100.
typestringobbligatorio"income" o "expense".
orderintegerobbligatorioPosizione di ordinamento all’interno del suo gruppo.
isPinnedbooleanobbligatorioFissa la categoria in cima al selettore.
categoryGroupIdstringfacoltativoId del gruppo padre, oppure null se senza gruppo.
iconstringfacoltativoIdentificatore dell’icona.
colorstringfacoltativoColore esadecimale.
PUT /api/v1/categories/{id} categories:write

Sostituisce una categoria utente. Il corpo è identico a Crea.

DELETE /api/v1/categories/{id} categories:write

Elimina logicamente una categoria utente. Le transazioni non vengono eliminate; il loro campo categoryId viene azzerato.

Gruppi di categorie

GET /api/v1/categories/groups categories:read

Elenca i tuoi gruppi di categorie.

GET /api/v1/categories/groups/{id} categories:read

Recupera un gruppo di categorie.

POST /api/v1/categories/groups categories:write

Crea un gruppo di categorie.

Corpo della richiesta
CampoTipoDescrizione
namestringobbligatorioNome visualizzato. Massimo 100.
orderintegerobbligatorioPosizione di ordinamento.
iconstringfacoltativoIdentificatore dell’icona.
colorstringfacoltativoColore esadecimale.
PUT /api/v1/categories/groups/{id} categories:write

Sostituisce un gruppo di categorie.

DELETE /api/v1/categories/groups/{id} categories:write

Elimina logicamente un gruppo. Le categorie figlie sopravvivono: il loro campo categoryGroupId viene azzerato.

Budget

Un budget limita la spesa su una categoria (oppure, quando categoryId è null, sull’intero registro) in una finestra temporale ricorrente. Condividi un budget con un gruppo impostando groupId.

GET /api/v1/budgets budgets:read

Elenca tutti i budget.

GET /api/v1/budgets/{id} budgets:read

Recupera un budget.

POST /api/v1/budgets budgets:write

Crea un budget.

Corpo della richiesta
CampoTipoDescrizione
amountnumberobbligatorioLimite per periodo. Deve essere maggiore di 0.
currencyCodestringobbligatorioISO-4217.
periodintegerobbligatorio0 settimanale · 1 mensile · 2 trimestrale · 3 annuale.
startDatestring (ISO-8601)obbligatorioInizio del primo periodo.
isActivebooleanobbligatorioIndica se il budget è attualmente applicato.
endDatestring (ISO-8601)facoltativoInterrompe il monitoraggio dopo questa data.
namestringfacoltativoEtichetta. Massimo 200.
categoryIdstringfacoltativoCategoria da monitorare. Ometti per applicare il budget a tutte le spese.
groupIdstringfacoltativoGruppo con cui condividere. Ometti per un budget personale.
PUT /api/v1/budgets/{id} budgets:write

Sostituisce un budget.

DELETE /api/v1/budgets/{id} budgets:write

Elimina logicamente un budget.

Gruppi

I gruppi sono registri condivisi: una famiglia, un viaggio, una casa condivisa. Ogni membro vede le stesse transazioni; la proprietà resta personale. Membri e inviti si gestiscono nell’app iOS; qui l’API espone la risorsa in sé.

GET /api/v1/groups groups:read

Elenca i gruppi di cui sei proprietario o membro.

GET /api/v1/groups/{id} groups:read

Recupera un gruppo.

POST /api/v1/groups groups:write

Crea un gruppo. Ne diventi il proprietario; invita i membri dall’app iOS.

Corpo della richiesta
CampoTipoDescrizione
namestringobbligatorioNome visualizzato. Massimo 100.
descriptionstringfacoltativoTesto libero. Massimo 500.
iconstringfacoltativoIdentificatore dell’icona.
colorstringfacoltativoColore esadecimale.
PUT /api/v1/groups/{id} groups:write

Sostituisce i metadati di un gruppo.

DELETE /api/v1/groups/{id} groups:write

Elimina logicamente un gruppo. I membri perdono la visibilità; le transazioni sottostanti tornano personali.

Transazioni

Le transazioni sono i verbi del registro. Esistono in quattro forme: income, expense, transfer (da conto a conto) e adjustment (riallineamento una tantum). L’endpoint di base crea entrate e spese; i trasferimenti hanno un endpoint dedicato; per gli importatori ad alto volume esistono le varianti in blocco.

GET /api/v1/transactions transactions:read

Elenca le transazioni con paginazione a cursore e filtri.

Parametri di query
CampoTipoDescrizione
limitintegerfacoltativoDimensione della pagina. 1..200. Valore predefinito 50.
cursorstringfacoltativoToken di continuazione opaco, ottenuto dalla risposta precedente.
typestringfacoltativo"income", "expense", "transfer" o "adjustment".
dateFromstring (ISO-8601)facoltativoLimite inferiore incluso.
dateTostring (ISO-8601)facoltativoLimite superiore incluso.
categoryIdstringfacoltativoFiltra su una sola categoria.
accountIdstringfacoltativoFiltra su un solo conto.
groupIdstringfacoltativoFiltra su un gruppo condiviso.
200 OK
{
  "items": [ /* TransactionDto[] */ ],
  "totalCount": 317,
  "nextCursor": "eyJrIjoiMjAyNi0wNS0xM1QxMDoz…"
}
GET /api/v1/transactions/{id} transactions:read

Recupera una transazione.

POST /api/v1/transactions transactions:write

Crea una singola transazione di entrata o di spesa. Per i trasferimenti, usa /transfer.

Corpo della richiesta
CampoTipoDescrizione
typestringobbligatorio"income" o "expense".
amountnumberobbligatorioImporto positivo in currencyCode.
currencyCodestringobbligatorioISO-4217.
datestring (ISO-8601)obbligatorioQuando è avvenuta la transazione (UTC).
accountIdstringfacoltativoConto di origine o di destinazione.
categoryIdstringfacoltativoEtichetta di categoria.
payeestringfacoltativoEsercente o controparte. Massimo 200.
notestringfacoltativoNota in testo libero. Massimo 2000.
groupIdstringfacoltativoCondivide con un gruppo.
exchangeRatenumberfacoltativoTasso di cambio quando currencyCode ≠ valuta principale dell’utente.
convertedAmountnumberfacoltativoImporto nella valuta principale dell’utente.
RichiestaCaffè da €8.50 ieri su Wise
POST /api/v1/transactions
{
  "type": "expense",
  "amount": 8.50,
  "currencyCode": "EUR",
  "date": "2026-05-12T09:14:00Z",
  "accountId": "acc_01HK8V…",
  "categoryId": "cat_food_drinks",
  "payee": "Pret",
  "note": "Flat white"
}
PUT /api/v1/transactions/{id} transactions:write

Sostituisce una transazione. Il corpo è identico a Crea.

DELETE /api/v1/transactions/{id} transactions:write

Elimina logicamente una transazione.

POST /api/v1/transactions/transfer transactions:write

Crea un trasferimento tra due conti. Nessuna categoria. Per i trasferimenti tra valute diverse, indica exchangeRate e convertedAmount nella valuta di destinazione.

Corpo della richiesta
CampoTipoDescrizione
fromAccountIdstringobbligatorioConto di origine.
toAccountIdstringobbligatorioConto di destinazione. Deve essere diverso da quello di origine.
amountnumberobbligatorioImporto inviato, in currencyCode.
currencyCodestringobbligatorioValuta di origine, ISO-4217.
datestring (ISO-8601)obbligatorioData del trasferimento.
exchangeRatenumberfacoltativoObbligatorio quando la valuta di origine e quella di destinazione sono diverse.
convertedAmountnumberfacoltativoImporto accreditato sul conto di destinazione, nella valuta di quest’ultimo.
notestringfacoltativoMassimo 2000.

Operazioni in blocco

Pensate per gli importatori. Ogni lotto è limitato a 100 elementi e viene eseguito in modalità best-effort: una singola riga errata non annulla le altre. Gli elementi riusciti e gli errori riga per riga vengono riportati separatamente, così puoi riprovare solo quelli non riusciti.

POST /api/v1/transactions/bulk transactions:write

Crea fino a 100 transazioni in un’unica chiamata.

200 OK
{
  "items": [ /* successful TransactionDto[] */ ],
  "errors": [
    { "index": 3, "error": "Invalid currency code" }
  ]
}
PUT /api/v1/transactions/bulk transactions:write

Aggiorna fino a 100 transazioni in un’unica chiamata. Ogni elemento deve includere il proprio id insieme al corpo completo della transazione.

POST /api/v1/transactions/bulk-delete transactions:write

Elimina logicamente fino a 100 transazioni in un’unica chiamata. Usa POST anziché DELETE, così il corpo della richiesta viene accettato da tutti i client HTTP.

Corpo della richiesta
CampoTipoDescrizione
idsstring[]obbligatorioDa 1 a 100 id di transazioni.
200 OK
{
  "deleted": 97,
  "notFound": [ "tx_old1", "tx_old2", "tx_old3" ]
}

L’oggetto transazione

CampoTipoDescrizione
idstringIdentificatore opaco.
typestringincome · expense · transfer · adjustment.
amountnumberEspresso in currencyCode.
currencyCodestringISO-4217.
exchangeRatenumber | nullValorizzato sulle voci in valuta diversa.
convertedAmountnumber | nullLo stesso valore nella valuta principale dell’utente.
datestringISO-8601 UTC.
accountIdstring | nullNei trasferimenti è il conto di origine.
toAccountIdstring | nullConto di destinazione, solo nei trasferimenti.
categoryIdstring | nullNull nei trasferimenti.
groupIdstring | nullValorizzato se la transazione è condivisa con un gruppo.
payeestring | nullEsercente o controparte.
notestring | nullTesto libero.
receiptImagePathstring | nullPercorso dello scontrino allegato. Recuperalo tramite l’endpoint degli scontrini (separato da v1).
recurringTransactionIdstring | nullValorizzato se la riga è stata generata da una regola ricorrente.
sourcestringTag di origine — api, mobile, web, import, ecc.
createdAtstringISO-8601 UTC.
updatedAtstringISO-8601 UTC.

Icone

Manilo include un set di icone curato e una palette di colori usati ovunque: conti, categorie, gruppi. Recupera il catalogo una volta sola, mettilo in cache e riusa gli identificatori quando crei le risorse.

GET /api/v1/icons

Restituisce l’intera libreria di icone, raggruppata per categorie, insieme alla palette di colori supportata. È versionata: si può mettere in cache in sicurezza in base al campo version.

200 OK
{
  "version": "2026.05.10",
  "library": "font-awesome-6",
  "categories": [
    {
      "id": "finance",
      "name": "Finance",
      "icons": [ "wallet", "credit-card", "piggy-bank" ]
    }
  ],
  "colors": [
    { "name": "Blue", "hex": "#4A90E2" },
    { "name": "Green", "hex": "#22C55E" }
  ]
}

Versionamento

  • Nessuna modifica incompatibile all’interno di v1. Aggiungeremo soltanto nuovi endpoint, nuovi campi facoltativi e nuovi valori di enum. Il tipo di un campo, la sua nullabilità o la sua obbligatorietà non cambieranno.
  • I nuovi valori di enum non sono modifiche incompatibili. Tratta i valori sconosciuti di type, source o action come “da non renderizzare” invece di andare in crash: li aggiungeremo man mano che il prodotto cresce.
  • Le modifiche incompatibili datate (se mai fossero necessarie) verranno rilasciate sotto /api/v2/ con almeno 6 mesi di disponibilità in parallelo e un’intestazione di deprecazione sulle risposte v1.

Assistenza

Hai trovato un bug, ti serve un endpoint o ti sei imbattuto in qualcosa di non documentato? Apri il centro assistenza oppure scrivi a support@manilo.app — quando segnali un problema, includi l’id della richiesta (riportato nell’intestazione di risposta X-Request-Id).

Per segnalazioni sensibili sul piano della sicurezza (un token trapelato, un aggiramento dei permessi, una lettura non autorizzata) scrivi a security@manilo.app.