StayLex StayLex

Documentazione

Una chiamata, l'imposta dovuta, la delibera

L'API restituisce quanto è dovuto per un soggiorno in un Comune italiano, con gli estremi dell'atto da cui viene il numero. REST, JSON, nessun SDK da installare, niente da sincronizzare.

308 Comuni letti sulle delibere, uno per uno.

Come funziona

Un endpoint, una chiamata POST. Si mandano il Comune, le date, la tipologia di struttura e gli ospiti; torna l'importo con il dettaglio di come è stato calcolato e la fonte normativa.

Non c'è niente da importare: nessun file di tariffe da tenere aggiornato, nessuna sincronizzazione periodica. Il dato sta da noi e viene mantenuto da noi.

ENDPOINT

POST https://staylex.io/v1/tourist-tax/quote
Content-Type: application/json
x-api-key: <la vostra chiave>

RICHIESTA

{
  "municipality": { "istat_code": "027042" },
  "check_in":  "2026-08-10",
  "check_out": "2026-08-14",
  "property_type": "hotel_4",
  "cadastral_category": "A/2",     // solo dove serve
  "guests": [
    { "age": 42 },
    { "age": 39 },
    { "age": 8 }
  ]
}

RISPOSTA

{
  "municipality": { "istat_code": "027042", "name": "Venezia", "province": "VE" },
  "total_due": 36,
  "currency": "EUR",
  "breakdown": {
    "nights": 4,
    "taxable_nights": 4,
    "night_cap": 5,
    "guests": 3,
    "taxable_guests": 2,
    "rate_per_night": 4.5,   // numero, OPPURE la stringa "variabile"
    "exemptions_applied": [
      { "guest_index": 2, "reason": "minor_under_10" }
    ],
    "exemptions_to_verify": [
      { "code": "studenti_universitari_fuori_sede",
        "requires_document": true }
    ]
  },
  "source": {
    "resolution": "Del. C.C. n. 42 del 27/11/2024 ...",
    "valid_from": "2025-01-01",
    "verified_on": "2026-08-24"
  }
}

Il riepilogo per ospite. Ogni risposta porta anche guest_summary: per ciascun ospite lo stato (paga, esente, ridotto, oltre il tetto), il motivo in parole, le notti addebitate e la quota dell'importo; e le righe pronte da mostrare, in italiano e in inglese (lines_it, lines_en): «2 ospiti × 3 notti × 4,50 € = 27,00 € · 1 ospite esente: minore di 10 anni · Totale: 27,00 €». È una ripartizione del totale, non un secondo calcolo: la somma torna al centesimo.

Due campi che valgono più del totale.

exemptions_applied dice quali esenzioni sono state applicate e a quale ospite: è quello che si mostra in caso di controllo.

exemptions_to_verify elenca le esenzioni che il Comune prevede ma che richiedono un documento — studenti, disabili, forze dell'ordine. Non le applichiamo noi: le segnaliamo, perché la verifica spetta a chi ospita.

L'API in cinque minuti

Quello che serve a un responsabile tecnico per capire se l'integrazione è fattibile, senza leggere il resto.

1 · AUTENTICAZIONE

Una chiave nell'header x-api-key. Nessun OAuth, nessun token da rinnovare, nessun SDK da installare. La chiave non scade.

x-api-key: sk_partner_xxxxxxxx

2 · UNA CHIAMATA, UNA RISPOSTA

Un solo endpoint per il calcolo. Nessuna sessione, nessuno stato: la stessa richiesta dà sempre la stessa risposta, e si può ripetere senza effetti collaterali.

POST /v1/tourist-tax/quote     // il calcolo
GET  /v1/municipalities        // i Comuni coperti
GET  /v1/coverage              // copertura e date di verifica

3 · OGNI RISPOSTA DICE DA QUALE ARCHIVIO VIENE

Un'intestazione su tutte le risposte, comprese quelle d'errore:

x-staylex-rules-version: 2026-09-10

Serve a rendere riproducibile un calcolo. Se fra sei mesi un Comune contesta un importo, si può dimostrare quale versione dell'archivio era in uso quel giorno — e se nel frattempo il dato è cambiato, si vede.

3-bis · rate_per_night PUÒ NON ESSERE UN NUMERO

Quando la tariffa cambia durante il soggiorno — stagione che gira, riduzione che scatta dopo N notti — un solo numero mentirebbe. In quel caso rate_per_night vale la stringa "variabile" e i tronconi veri stanno in rates_by_night:

"rate_per_night": "variabile",
"rates_by_night": [
  { "rate_per_night": 2.0, "nights": 5 },
  { "rate_per_night": 1.0, "nights": 15 }
]

Riguarda 84 Comuni su 308. Un client tipizzato che mappa quel campo a number va in eccezione su una prenotazione estiva ordinaria: va letto come numero oppure stringa, e per i conti si usa sempre rates_by_night, che c'è in entrambi i casi.

4 · GLI ERRORI HANNO UN CODICE, NON SOLO UN TESTO

Il messaggio è in italiano e può essere riformulato. Il codice no: è stabile e si può usare per ramificare il codice.

{
  "detail": "Desenzano del Garda: la tariffa dipende dalla
             categoria catastale — il campo cadastral_category
             è obbligatorio (es. "A/2")",
  "code": "missing_cadastral_category"
}
CodiceHTTPQuando
municipality_not_covered404 Il Comune non è nell'archivio. Non stimiamo: lo diciamo.
missing_cadastral_category422 Quel Comune tariffa per categoria catastale e il campo manca.
property_type_not_in_act422 L'atto comunale non prevede quella tipologia di struttura.
period_not_covered422 Conosciamo la regola solo da una certa data in poi: per il soggiorno chiesto non rispondiamo. Il messaggio dice da quando rispondiamo.
invalid_dates422 Date mancanti, in formato diverso da AAAA-MM-GG, inesistenti nel calendario, oppure check-out non successivo al check-in.
invalid_guest_age422 Età non intera, negativa o oltre 120.
missing_rental_amount422 Quel Comune tariffa a fasce di prezzo o a percentuale sul canone: serve rental_amount.
invalid_rental_amount422 rental_amount presente ma non positivo.
no_applicable_price_band422 Nessuna fascia di prezzo dell'atto copre quel canone.
no_rate_for_month422 L'atto non prevede tariffa per quel mese (imposta stagionale).
missing_property_qualification422 L'esenzione richiesta vale solo per certi immobili: serve property_qualification.
no_guests422Nessun ospite nella richiesta.
missing_property_ref422 La vostra chiave richiede property_ref e manca. Nel riepilogo, il campo stays dell'errore elenca gli indici dei soggiorni senza.
invalid_property_ref422 property_ref più lungo di 64 caratteri o con caratteri non ammessi.
missing_fields422 Manca uno fra municipality.istat_code, check_in, check_out, guests.
invalid_body422Il corpo non è JSON valido.
invalid_key401Chiave assente o non valida.
forbidden403Endpoint non incluso nella chiave.
not_found404Rotta inesistente.

⚠️ I codici di esenzione sono per Comune, non un vocabolario globale. `minori` significa cose diverse in Comuni diversi, perché diverse sono le soglie fissate dagli atti. Chi riusa lo stesso codice su più Comuni crede di invocare la stessa regola e ne invoca un'altra: i codici applicabili sono sempre quelli che la risposta elenca in `exemptions_to_verify` per quel Comune.

5 · LIMITI DI CHIAMATA E VERSIONI

Le chiavi di valutazione sono limitate a 120 chiamate al giorno e 10 al minuto; quelle dei piloti a 200 e 20. Oltre la soglia la risposta è un 429.

La versione dell'API sta nell'indirizzo (/v1/) e non cambia in modo incompatibile: i campi si aggiungono, non si tolgono né si rinominano. Se un giorno servisse un cambiamento incompatibile, nascerebbe /v2/ e /v1/ resterebbe attivo.

Cosa non c'è, per essere chiari. Non ci sono webhook: gli aggiornamenti si vedono interrogando /v1/coverage, che riporta per ogni Comune la data dell'ultima verifica. Non c'è uno schema OpenAPI pubblicato. Non c'è un contratto di livello di servizio sull'uptime — c'è l'impegno sui tempi di aggiornamento del dato, che è la cosa per cui si paga: dieci giorni dalla pubblicazione dell'atto, cinque sui Comuni prioritari.

Se una di queste cose vi serve per integrare, scrivetemi: alcune sono già in programma e i primi partner decidono l'ordine.

I parametri

CampoObbligatorioNote
municipality.istat_codesì Codice ISTAT a sei cifre. In alternativa name, ma il codice è più sicuro.
check_in / check_outsì Formato ISO (AAAA-MM-GG). Le notti si contano fra le due date.
property_typesì Una fra venti tipologie: hotel_1…hotel_5, short_term_rental, b_and_b, affittacamere, campsite, agriturismo…
guests[].ageconsigliato Senza le età l'ospite è trattato come adulto. Le esenzioni per i minori valgono in 304 Comuni su 308.
contract_typeconsigliato `short_stay` oppure `residential_lease`. Il presupposto dell'imposta è il pernottamento in struttura ricettiva o la locazione breve ex art. 4 D.L. 50/2017 (fino a 30 giorni): una locazione abitativa ordinaria ne sta fuori e la risposta è zero dichiarato, non un importo. Senza questo campo calcoliamo come un soggiorno turistico.
contract_daysconsigliato Durata del CONTRATTO, che può essere più lunga del soggiorno prenotato. Oltre 30 giorni vale come `residential_lease`.
property_qualificationa volte `student_housing`, `university_residence`, `tourist_rental`, `other`. Serve dove l'esenzione dipende dall'IMMOBILE e non dall'ospite: a Milano gli studenti sono esenti «solo in strutture, pensionati o residenze universitarie», a Bologna «solo in studentati». Senza il campo la richiesta viene rifiutata invece di essere concessa a caso.
booked_ona volte La data della prenotazione (AAAA-MM-GG). Serve dove l'atto fa salve le prenotazioni già effettuate prima della nuova tariffa (Genova, DGC-2026-166: le prenotazioni anteriori al 01/08/2026 pagano le tariffe precedenti). Senza il campo si applica la tariffa vigente al check-in e la risposta lo dice in booking_date_hint.
cadastral_categorya volte Serve dove la tariffa dipende dalla categoria catastale. Se manca, l'API restituisce un errore che lo dice.
rental_amounta volte Serve dove la tariffa è una percentuale del canone o dipende da fasce di prezzo.
property_refper i partner a contratto Il vostro identificativo dell'alloggio, anche già cifrato (da 1 a 64 caratteri fra lettere, cifre e . _ : - / #). Serve a contare gli alloggi serviti nel mese, su cui si misura la fascia del contratto. Non lo conserviamo: teniamo solo un'impronta che permette di contare gli alloggi distinti. Va inviato anche in ogni soggiorno di /v1/summary e in /v1/self-declaration.

La riga per la fattura

Ogni calcolo con imposta maggiore di zero restituisce invoice_line: la riga da copiare nella fattura che emette chi vende il soggiorno, per gli ospiti che la chiedono (descrizione in italiano e inglese, importo, natura IVA N1, riferimento art. 15, c. 1, n. 3, D.P.R. 633/1972). Codice fiscale e partita IVA dell'ospite restano nel vostro sistema di fatturazione: non servono a noi. È un'indicazione di prassi, da confermare con il vostro consulente fiscale.

Cosa si conta in fattura

Per i partner a contratto ogni mese si contano due cose, dal registro che l'API scrive a ogni risposta riuscita (HTTP 200). Le risposte di errore non si contano mai.

VoceCome si conta
alloggialloggi distinti (property_ref) con almeno una risposta 200 nel mese
POST /v1/tourist-tax/quote1 chiamata
POST /v1/summary1 chiamata per ogni soggiorno calcolato (stays_computed)
POST /v1/self-declaration1 chiamata
copertura, moduli, cartellonon si contano: sono dati di riferimento, da tenere in cache

Quando l'API dice di non sapere

Un fornitore che dice «questo non lo so» è l'unico di cui ci si può fidare quando dice «questo lo so».

Se il Comune non è coperto, o se manca un dato indispensabile, l'API non stima: risponde con un errore che spiega cosa manca.

// Comune non ancora mappato
{
  "detail": "Comune 012345 non coperto: il servizio risponde sui Comuni italiani, identificati dal codice ISTAT a sei cifre. Per sapere se un Comune e' coperto usare /v1/coverage",
  "code": "municipality_not_covered",
  "country_scope": "IT"
}

// dato mancante
{
  "detail": "Desenzano del Garda: la tariffa dipende dalla categoria catastale
            — il campo cadastral_category è obbligatorio (es. \"A/2\")"
}

// tipologia non prevista dall'atto
{
  "detail": "Moniga del Garda: nessuna tariffa applicabile a property_type=rifugio
            — l'atto comunale non prevede questa tipologia"
}

Gli altri endpoint

EndpointCosa fa
GET /v1/municipalities L'elenco dei Comuni coperti, con codice ISTAT, provincia e regione.
GET /v1/coverage Per ogni Comune: quali tipologie sono coperte, quando è stato verificato, quando è prevista la prossima revisione.
POST /v1/demo/quote Come quote ma senza chiave, limitato a cinquanta destinazioni. Serve a provare senza registrarsi.
GET /v1/form-template/{istat} Il modulo per l'ospite di quel Comune, costruito dagli atti: i campi da chiedere sempre (età, residenza con la domanda giusta), le sole caselle di esenzione che l'atto prevede, le impostazioni per immobile (zona, categoria catastale, classificazione, data di prenotazione dove servono) e le voci da non mostrare mai all'ospite. Parametro ?property_type= (predefinito short_term_rental).
POST /v1/self-declaration La dichiarazione sostitutiva dell'atto di notorietà (art. 47 D.P.R. 445/2000) per un'esenzione documentale, con il testo esatto dell'atto e l'articolo: precompilata con i dati inviati (guest, stay, host) o con gli spazi da compilare. format=html restituisce la pagina stampabile. Nulla viene conservato.
GET /v1/notice/{istat} Il cartello da esporre nella struttura (obbligo di informazione dei regolamenti): tariffe della tipologia, tetto, periodo, esenzioni automatiche e con dichiarazione, riduzioni — in italiano e inglese, con il regolamento citato. format=html per la pagina stampabile.
POST /v1/summary Un elenco di soggiorni (fino a 500, nel formato di quote) e indietro i totali per Comune e per mese: presenze, imponibili, esenti per motivo, oltre il tetto, importo — la base della dichiarazione periodica al Comune. I soggiorni che non si calcolano sono elencati a parte, mai sommati.

Aggiornamenti e limiti

Le fonti comunali sono sorvegliate automaticamente: quando la pagina che pubblica gli atti cambia, il sistema se ne accorge, scarica il nuovo atto e lo confronta con quello in archivio.

L'impegno è di dieci giorni dalla pubblicazione dell'atto per aggiornare il dato, cinque sui Comuni che il partner indica come prioritari. Non promettiamo il tempo reale: un atto va letto, e leggerlo bene richiede più di un aggiornamento automatico.

Cosa non facciamo. Non riscuotiamo e non versiamo: non tocchiamo denaro e non ci sostituiamo ai portali dei Comuni. Non facciamo la dichiarazione periodica. Non copriamo ancora tutti i Comuni italiani — sono circa 1.400 quelli che hanno istituito l'imposta, noi ne abbiamo letti 308.

Chiavi e limiti di chiamata

La chiave si passa nell'header x-api-key. Le chiavi di valutazione hanno un limite di 120 chiamate al giorno e 10 al minuto; quelle dei piloti 200 e 20. I limiti dei piani sono sulla pagina dei prezzi.

Nessun dato personale transita dall'API: le età degli ospiti sono numeri, non identità. Non riceviamo né conserviamo nomi, documenti o recapiti.

Una chiave di prova, gratuita e senza scadenza

Uno schema solo per tutti i Comuni, nessun SDK, nessuna sincronizzazione. Scrivetemi indicando il vostro sistema e i Comuni che vi interessano di più: preparo la chiave e, se serve, mappo quei Comuni per primi.

Chiedi la chiave

Documentazione aggiornata al 05/10/2026 · 308 Comuni · Ogni risposta cita la delibera da cui viene il numero. Per il metodo e i limiti dichiarati — metodo e limiti, prezzi.