Integrazione Market Scanner
Le API dello Scanner di Dokicasa permettono di ottenere visure, ispezioni, note, mappe catastali e ricerche da indirizzo. Sono asincrone: questa guida ti mostra come riceverne i risultati nel modo più efficiente, evitando il polling quando possibile.
🎮 Prova le API dal vivo
Apri il Playground interattivo: incolli il tuo token, lanci ogni chiamata in sandbox e vedi arrivare socket e polling in tempo reale, testi i webhook, e copi il codice pronto in cURL, Python, Node, JavaScript e PHP.
| Base URL | https://api.dokicasa.it |
| Auth | Authorization: Bearer <api_token> |
| Content-Type | application/json |
Documentazione e autenticazione
La documentazione interattiva di tutti gli endpoint è su Swagger, sezione Scanner: api.dokicasa.it/api/documentation#/Scanner (ricerche, polling, recupero risultati).
Tutte le chiamate vanno autenticate con un Bearer token:
Authorization: Bearer YOUR_API_TOKENWARNING
Il token non deve mai finire in repo pubblici o sul frontend: trattalo come una password.
Endpoint principali
Tabella riassuntiva — lo schema completo è su Swagger.
| Metodo | Path | Cosa fa |
|---|---|---|
POST | /api/scanner/{type} | Crea una richiesta scanner (visura / ispezione / mappa / list-addresses / …). Ritorna scanner_request_id. |
GET | /api/scanner-request/{id} | Stato richiesta + risultato. Per i PDF qui trovi il link result.pdf_path (il file NON è nel JSON: si scarica dal link); per list-addresses i dati sono già nel JSON. |
GET | /api/scanner-request/{id}/results | Risultati strutturati per le ricerche "normali" (es. immobili da indirizzo). |
| WS | private-scanner_request.{id} | Canale WebSocket privato per gli aggiornamenti realtime. |
Stati della richiesta
ENQUEUED → SCANNING → SUCCESS
╲→ ERRORENQUEUED e SCANNING sono transitori; SUCCESS ed ERROR sono finali.
Tipi di interrogazione
Ogni interrogazione è un POST /api/scanner/{type}. Qui sotto i type disponibili (lo schema dei parametri di ognuno è sullo Swagger, sezione Scanner).
Ricerche dati — il risultato è JSON nel campo result:
type | Cosa fa | Campo in result |
|---|---|---|
search-fiscal-code | Codice fiscale da nome, cognome e provincia | anagrafiche |
tax-data | Immobili posseduti da un CF / P.IVA | immobili |
catasto | Immobili da foglio / particella | immobili |
intestatari-catasto | Proprietari di una particella | intestatari |
list-addresses | Normalizza un indirizzo → lista di vie | addresses |
immobili-by-name | Immobili a livello nazionale da nome/cognome (2 fasi) | immobili |
Documenti — nessuna chiamata API restituisce il PDF: nel campo result.pdf_path trovi il link da cui scaricarlo (vedi nota sotto):
type | Documento |
|---|---|
visura-catasto / visura-tax-data | Visura catastale (da dati catastali / da CF-P.IVA) |
ispezione-catasto / ispezione-tax-data | Ispezione ipotecaria |
nota-catasto / nota-tax-data | Nota di trascrizione |
mappa-catasto | Mappa catastale |
elaborato-planimetrico | Elaborato planimetrico |
elenco-immobili | Elenco immobili |
IMPORTANT
catasto ≠ visura catastale. catasto è la ricerca immobili da foglio/particella e restituisce l'elenco immobili (dati JSON). La visura catastale in PDF è invece visura-catasto (da dati catastali) o visura-tax-data (da CF/P.IVA). Analogamente la visura/ispezione ipotecaria è ispezione-catasto / ispezione-tax-data.
TIP
Le ispezioni e le note richiedono il comune nel body: serve a risolvere la conservatoria competente.
IMPORTANT
Le chiamate API non restituiscono mai il PDF: restituiscono solo il link result.pdf_path. Il file va scaricato con una GET separata su quel link, passando il tuo Bearer token (endpoint autenticato, non un link pubblico anonimo). Il link è stabile e permanente (non scade): puoi salvarlo e riutilizzarlo come riferimento in una tua procedura.
⚠️ Con curl la risposta è binaria (Content-Type: application/pdf): senza -o curl non stampa nulla sul terminale (sembra un "200 vuoto"), ma il file c'è. Salvalo:
curl -o visura.pdf "<pdf_path>" -H "Authorization: Bearer <TOKEN>"immobili-by-name — ricerca in due fasi
immobili-by-name cerca gli immobili di una persona a livello nazionale partendo da nome e cognome. Poiché possono esserci più omonimi, funziona in due fasi.
Fase 1 — lista degli omonimi
POST /api/scanner/immobili-by-name con solo nome e cognome:
{ "first_name": "CHRISTIAN", "last_name": "CANNATA" }Al termine (via socket/polling, come ogni chiamata async) il result contiene la lista degli omonimi trovati:
{
"needs_selection": true,
"omonimi": [
{
"value": "9800054753#0#CANNATA#CHRISTIAN#CNNCRS91D08E625S#LIVORNO#08/04/1991#LI",
"nome": "CHRISTIAN", "cognome": "CANNATA",
"codice_fiscale": "CNNCRS91D08E625S",
"data_nascita": "08/04/1991", "luogo_nascita": "LIVORNO (LI)", "sesso": "M"
}
// … altri omonimi
]
}needs_selection: true→ devi scegliere una persona dalla lista.- Se c'è un solo omonimo la selezione è automatica: ottieni subito il risultato della Fase 2.
Fase 2 — immobili della persona scelta
Richiama lo stesso endpoint aggiungendo selected_value = il campo value dell'omonimo scelto nella Fase 1 (copialo tale e quale):
{
"first_name": "CHRISTIAN",
"last_name": "CANNATA",
"selected_value": "9800054753#0#CANNATA#CHRISTIAN#CNNCRS91D08E625S#LIVORNO#08/04/1991#LI"
}Al termine il result contiene:
{
"omonimo_selezionato": { "value": "…", "nome": "CHRISTIAN", "cognome": "CANNATA" },
"immobili": { "…": "…" },
"has_soppressi": false
}Gli immobili sono persistiti: la lista completa (con intestatari) si recupera paginata da GET /api/scanner-request/{id}/results.
NOTE
Entrambe le fasi sono normali chiamate async: la POST torna ENQUEUED, poi via socket o polling arrivi a SUCCESS e leggi il result. Nomi molto comuni possono superare il limite di risultati della Fase 1: restringi con dati più specifici.
Come funziona
Tutte le chiamate scanner sono asincrone. Il flusso è sempre lo stesso, cambia solo come ricevi l'aggiornamento di stato.
- Crei la richiesta —
POST /api/scanner/{type}→ ricevi unoscanner_request_ide lo stato inizialeENQUEUED. - Attendi il completamento — scegli uno di questi modi (in ordine di preferenza):
- WebSocket — push istantaneo, nessun polling.
- Webhook callback — il nostro server chiama il tuo a fine elaborazione.
- Polling (fallback) — solo se non puoi usare i due sopra.
- Ottieni il risultato — quando lo stato è
SUCCESS:- PDF (visure, ispezioni, mappe, note): il file è già nella risposta di
GET /api/scanner-request/{id}. - Ricerche strutturate: chiama
GET /api/scanner-request/{id}/results.
- PDF (visure, ispezioni, mappe, note): il file è già nella risposta di
Aggiornamenti realtime via WebSocket
⭐ Consigliato per app frontend
Approccio raccomandato per web/mobile: nessun polling, aggiornamenti istantanei, barre di avanzamento e notifiche in push.
Ogni richiesta pubblica eventi su un canale privato dedicato:
private-scanner_request.{id}dove {id} è lo scanner_request_id ritornato dal POST iniziale.
Ambienti — host e chiave del socket
Il socket è separato per ambiente: usa host e chiave in base a dove chiami.
| Ambiente | Base URL API | wsHost (socket) | key | authEndpoint |
|---|---|---|---|---|
| Sandbox / test | https://api-dev.dokicasa.it | api-dev.dokicasa.it | staging | https://api-dev.dokicasa.it/broadcasting/auth |
| Produzione | https://api.dokicasa.it | socket.dokicasa.it | ra9jcihuz0sx7vtw8yut | https://api.dokicasa.it/broadcasting/auth |
WARNING
Non mischiare gli ambienti: se ti connetti al socket di produzione ma fai le chiamate in sandbox (o viceversa), il canale si iscrive ma non ricevi eventi (è un Reverb diverso). L'esempio sotto usa i valori di produzione; per la sandbox sostituisci key, wsHost e authEndpoint con la riga Sandbox.
Esempio completo (JavaScript + Pusher/Reverb)
import Pusher from 'pusher-js'
const apiToken = 'YOUR_API_TOKEN'
// 1. Client WebSocket (Reverb sul backend, API Pusher sul client)
const pusher = new Pusher('ra9jcihuz0sx7vtw8yut', {
wsHost: 'socket.dokicasa.it',
wsPort: 443,
wssPort: 443,
forceTLS: true,
cluster: 'mt1',
disableStats: true,
enabledTransports: ['ws', 'wss'],
authEndpoint: 'https://api.dokicasa.it/broadcasting/auth',
auth: { headers: { Authorization: 'Bearer ' + apiToken } },
})
// 2. Creo la richiesta scanner
const { scanner_request_id } = await fetch(
'https://api.dokicasa.it/api/scanner/intestatari-catasto',
{
method: 'POST',
headers: {
Authorization: 'Bearer ' + apiToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({
comune: 'Roma', provincia: 'RM',
foglio: '123', particella: '45',
search_catasto_type: 'F',
}),
}
).then((r) => r.json())
// 3. Mi iscrivo al canale e ascolto gli stati
const channel = pusher.subscribe(`private-scanner_request.${scanner_request_id}`)
channel.bind('ScannerRequestNotification', ({ message }) => {
const { status, percentage } = message
if (status === 'SCANNING') updateProgressBar(percentage)
if (status === 'SUCCESS') fetchResult(scanner_request_id)
if (status === 'ERROR') handleError(message)
})
async function fetchResult(id) {
const data = await fetch(`https://api.dokicasa.it/api/scanner-request/${id}`, {
headers: { Authorization: 'Bearer ' + apiToken },
}).then((r) => r.json())
console.log('Risultato finale:', data)
}✓ Pro: nessun polling, ricezione istantanea, UX migliore. Funziona ovunque ci sia un client WS (web, mobile, server con client Pusher).
Webhook e firma
⭐ Consigliato per integrazioni backend
Passi un URL nella creazione della richiesta: a fine elaborazione Dokicasa ti POSTa il risultato. Invio asincrono con retry — nessuna configurazione nel pannello.
Ci sono due campi che puoi mettere nel body del POST iniziale (anche entrambi insieme):
| Campo (nel body POST) | Payload che ricevi | Quando parte |
|---|---|---|
callback | compatto: { id, type, status, percentage, result, created_at, updated_at, finished_at } | a fine scansione |
webhook | completo: { scanner_request: { …oggetto richiesta intero, con paramseresult… } } | sull'evento di completamento |
{
"type": "catasto",
"comune": "Roma", "foglio": "123", "particella": "45", "search_catasto_type": "F",
"callback": "https://tuo-server.com/dokicasa/scanner-callback",
"webhook": "https://tuo-server.com/dokicasa/scanner-webhook"
}Comuni divisi in sezioni catastali
In alcuni comuni — Roma, Napoli, Genova — foglio e particella da soli non bastano a individuare un immobile: serve anche la sezione catastale. In quei casi aggiungi sezione_comune alla richiesta.
{
"type": "catasto",
"comune": "Napoli", "provincia": "NA",
"sezione_comune": "SAN FERDINANDO",
"foglio": "123", "particella": "45"
}È facoltativo e concorre a identificare l'immobile insieme a foglio, particella, subalterno e comune: due immobili con la stessa particella ma sezione diversa restano distinti. Se lo ometti in un comune che le usa, la ricerca può restituire l'immobile sbagliato o non trovarlo.
Il nome del campo è sezione_comune: un sezione viene ignorato senza errore.
Il result che ricevi ha la forma che dipende dal tipo — vedi Formato dei risultati per tipo.
callback vs webhook — che differenza c'è
Stesso meccanismo (un POST firmato al tuo URL a fine elaborazione, con retry): cambia solo la forma del payload.
{
"id": 2615190,
"type": "VISURA-CATASTO",
"status": "SUCCESS",
"percentage": 98,
"result": { "pdf_path": "https://.../sample-visura-catasto", "is_empty": false },
"created_at": "2026-07-02T23:22:59+02:00",
"updated_at": "2026-07-02T23:23:02+02:00",
"finished_at": "2026-07-02T23:23:02+02:00"
}{
"scanner_request": {
"id": 2615190,
"user_id": 5128,
"type": "VISURA-CATASTO",
"params": { "comune": "ROMA", "provincia": "RM", "foglio": "123", "particella": "45", "tipo_visura": "ANALITICA" },
"result": { "pdf_path": "https://.../sample-visura-catasto", "is_empty": false },
"status": "SUCCESS"
}
}callback | webhook | |
|---|---|---|
| Payload | compatto, campi flat | oggetto scanner_request intero |
Include i params d'input | No | Sì |
Header Signature (HMAC) | Sì | Sì |
| Quando parte | a fine scansione | a fine scansione |
Quale usare
callback→ payload leggero: ti basta reagire all'esito (id,status,result). È la scelta più comune.webhook→ l'intero record, inclusi iparamsoriginali della richiesta: comodo per riconciliare/loggare senza tenere stato lato tuo.
Sono indipendenti: puoi passarne uno, l'altro, o entrambi (in quel caso ricevi due POST distinti). Entrambi firmati con l'header Signature.
Firma — verifica l'autenticità
Ogni webhook include l'header Signature: è l'HMAC-SHA256 del body grezzo, firmato con la tua api_token (la stessa che usi come Bearer). Così non devi gestire nessuna chiave nuova — verifichi con la tua api_key.
Signature = hash_hmac('sha256', <body_grezzo>, <la_tua_api_token>)$raw = file_get_contents('php://input'); // body GREZZO, non ri-serializzato
$expected = hash_hmac('sha256', $raw, $MY_API_TOKEN);
if (!hash_equals($expected, $_SERVER['HTTP_SIGNATURE'] ?? '')) {
http_response_code(401); exit; // firma non valida
}const crypto = require('crypto')
const raw = req.rawBody // body GREZZO (Buffer/stringa)
const expected = crypto.createHmac('sha256', MY_API_TOKEN).update(raw).digest('hex')
if (expected !== req.get('Signature')) return res.sendStatus(401)Firma sul body **grezzo**
Calcola l'HMAC sui byte esatti ricevuti, prima di parsare/ri-serializzare il JSON: reincodare cambia spazi e ordine delle chiavi, e la firma non combacia più.
Idempotenza
In caso di errori di rete l'invio viene ritentato: identifica la richiesta con l'id nel body e rispondi 2xx anche sui duplicati, così eviti retry inutili.
Formato dei risultati per tipo
Il campo result (lo trovi in GET /api/scanner-request/{id}, ed è lo stesso che arriva via socket e webhook) cambia forma a seconda del tipo di richiesta. Qui sotto le forme principali, con esempi reali.
`result` vs `/results`
result= payload completo della scansione (immobili, anagrafiche, PDF…), già pronto.GET /api/scanner-request/{id}/results= vista paginata dei soli immobili persistiti (con intestatari), comoda quando sono tanti. Vale per i tipi che listano immobili (catasto,tax-data,list-addresses,intestatari-catasto); restituisce un paginatore Laravel{ current_page, data: [...], links, ... }.
{
"has_soppressi": true,
"immobili": [
{
"foglio": "368", "particella": "435", "subalterno": "5",
"indirizzo": "VIA ESEMPIO n. 11 Interno 1 Piano S1 - T",
"comune": "ROMA", "provincia": "RM", "numero_civico": "11", "piano": "S1",
"categoria": "A02", "classe": "02", "consistenza": "6 vani", "rendita": "1239,50",
"catasto": "F", "codice_belfiore": "H501", "partita": "", "zona_cens": "004",
"scanner_immobili_id": 82659
},
{
"foglio": "368", "particella": "435", "subalterno": "24",
"indirizzo": "VIA ESEMPIO n. 19 Piano T",
"comune": "ROMA", "provincia": "RM", "numero_civico": "19", "piano": "T",
"categoria": "C01", "classe": "10", "consistenza": "46 m2", "rendita": "3594,44",
"catasto": "F", "codice_belfiore": "H501", "partita": "", "zona_cens": "004",
"scanner_immobili_id": 82678
}
]
}{
"intestatari": [
{
"nome_cognome": "ROSSI MARIO", "codice_fiscale": "RSSMRA80A01H501U",
"quota": "1/2", "titolarita": "Proprieta'",
"luogo_nascita": "ROMA", "data_nascita": "01/01/1980",
"comune": "ROMA", "provincia": "RM"
},
{
"nome_cognome": "ESEMPIO IMMOBILIARE SRL", "codice_fiscale": "01234567890",
"quota": "1/2", "titolarita": "Nuda proprieta'",
"luogo_nascita": "", "data_nascita": "",
"comune": "ROMA", "provincia": null
}
]
}{
"immobili": [],
"anagrafiche": [
{
"cognome": "ROSSI", "nome": "MARIO",
"data_di_nascita": "17/05/1938", "luogo_di_nascita": "MILANO (MI)",
"sesso": "M", "codice_fiscale": "RSSMRA38E17F205T"
}
]
}{
"addresses": {
"123494##VIA ROMA": " VIA ROMA ",
"337696##VIA ROMAGNOSI": " VIA ROMAGNOSI ",
"12428##VIALE ROMAGNA": " VIALE ROMAGNA "
}
}{
"pdf_path": "https://.../visure/<request_id>.pdf",
"request_id": "…",
"is_nota_negativa": false,
"is_empty": false
}Dove trovi lo schema di ogni singola chiamata
I parametri di input e il tipo esatto di ogni interrogazione (foglio/particella, tax_code, tipo_visura, ecc.) sono sullo Swagger, sezione Scanner: api.dokicasa.it/api/documentation#/Scanner. Questa pagina copre invece come ricevere e interpretare i risultati.
Come testare l'integrazione
C'è un ambiente sandbox — https://api-dev.dokicasa.it — che rispecchia le API di produzione ma non fa interrogazioni reali: ogni chiamata torna dati di esempio realistici, non consuma credito e non genera documenti reali. Rispetto alla produzione cambia solo il base URL: endpoint, parametri, formato risposte, WebSocket e webhook sono identici.
🔑 Chiave API di test (sandbox)
Usa questo token: è un utente con tutte le chiamate abilitate e gratuite, pensato apposta per provare. In sandbox la whitelist degli origin è disattivata, quindi puoi chiamare anche da localhost o da qualsiasi dominio di test.
HfBfYShns3E02no3kkwCRWQugkVNcJCtrRN2BPoI5NxhqsiXaxxnSPpIHY2OPassalo come header Authorization: Bearer <token> su ogni chiamata.
È già pronto nel Playground
Nel Playground interattivo questo token è precompilato (e copiabile): apri, premi Lancia e vedi socket + polling in tempo reale, senza configurare nulla.
Endpoint da testare
API — base https://api-dev.dokicasa.it
| Cosa | Endpoint |
|---|---|
| Avvia una ricerca | POST /api/scanner/{type} → { scanner_request_id, status } |
| Stato + risultato | GET /api/scanner-request/{id} · …/{id}/status |
| Risultati paginati | GET /api/scanner-request/{id}/results |
| Crea monitoraggio | POST /api/monitoring/from-catasto |
| Simula webhook (solo sandbox) | POST /api/user-monitorings/{id}/simulate-webhook |
Socket — sandbox (vedi anche Ambienti del socket)
| Parametro | Valore |
|---|---|
wsHost | api-dev.dokicasa.it |
key | staging |
authEndpoint | https://api-dev.dokicasa.it/broadcasting/auth |
| canale · evento | private-scanner_request.{id} · ScannerRequestNotification |
Prova rapida (curl)
curl -X POST https://api-dev.dokicasa.it/api/scanner/list-addresses \
-H "Authorization: Bearer HfBfYShns3E02no3kkwCRWQugkVNcJCtrRN2BPoI5NxhqsiXaxxnSPpIHY2O" \
-H "Content-Type: application/json" \
-d '{"indirizzo":"via roma","comune":"Milano","provincia":"MI"}'
# → { "scanner_request_id": 12345, "status": "ENQUEUED" }
# poi: GET /api/scanner-request/12345/status fino a status = SUCCESSCosa verificare:
- Flusso async — la POST torna
ENQUEUED, poi via socket (istantaneo) o polling arrivi aSUCCESS. - Forma delle risposte — mappa i campi del
result(vedi Formato risultati per tipo). - Webhook — punta
webhook_urla un inspector (webhook.site); in sandbox il monitoraggio invia subito un evento d'esempio alla creazione (o richiamalo con/simulate-webhook). - Firma — valida l'header
Signature(vedi sezione Firma).
NOTE
In sandbox i dati sono rappresentativi e fissi (non variano in base ai parametri): mostrano la struttura del result. Quando sei pronto, passa al base URL e al socket di produzione (tabella Ambienti del socket).
Monitoraggio immobili
Oltre alle ricerche una-tantum, puoi monitorare un immobile nel tempo: Dokicasa ricontrolla periodicamente i proprietari al catasto e, quando cambiano, ti invia una notifica webhook con la variazione.
Attivare il monitoraggio
POST /api/monitoring/from-catasto — parti direttamente dai dati catastali (non serve un id immobile). Se l'immobile non è ancora a sistema viene prima risolto con una ricerca catastale (proprietari inclusi) e salvato, poi il monitoraggio viene attivato.
{
"foglio": "123",
"particella": "45",
"subalterno": "7",
"comune": "Roma",
"provincia": "RM",
"webhook_url": "https://tuo-server.com/dokicasa/monitoring-changed"
}| Campo | Obbligatorio | Note |
|---|---|---|
foglio, particella | ✅ | la "tripletta" catastale |
subalterno | — | numerico, opzionale |
comune | ✅ | codice catastale o nome comune |
provincia | ✅ | sigla (no TN/BZ) |
search_catasto_type | — | F fabbricati (default) / T terreni |
sezione_comune | — | per comuni con sezioni (Napoli/Roma/Genova) |
webhook_url | — | URL a cui inviare le variazioni (vedi sotto) |
name, note | — | etichette libere |
Risposta: { immobile_id, user_monitoring_id, created, scanned, last_monitoring, next_monitoring } (last_monitoring = ultima esecuzione, null se mai girato; next_monitoring = prossima esecuzione).
Webhook di variazione proprietari
Se valorizzi webhook_url, ad ogni cambio proprietari rilevato dal monitoraggio Dokicasa fa una POST asincrona a quell'URL con il JSON completo della variazione:
{
"event": "immobile.owners_changed",
"user_monitoring_id": 12345,
"immobile": {
"id": 987, "foglio": "123", "particella": "45",
"subalterno": "7", "comune": "Roma", "provincia": "RM"
},
"changes": [
{
"date": "2026-07-01",
"differences": {
"added": [
{
"quota": "1/2", "nome": "Mario", "cognome": "Rossi", "denominazione": null,
"codice_fiscale": "RSSMRA80A01H501U", "partita_iva": null,
"dt_nascita": "1980-01-01", "comune_nascita": "Roma", "provincia_nascita": "RM", "sesso": "M"
}
],
"removed": [
{
"quota": "1/2", "nome": "Luigi", "cognome": "Verdi", "denominazione": null,
"codice_fiscale": "VRDLGU75M15F205X", "partita_iva": null,
"dt_nascita": "1975-08-15", "comune_nascita": "Milano", "provincia_nascita": "MI", "sesso": "M"
}
],
"modified": [
{
"id": "CF:BNCLNA82H41H501Y",
"before": {
"quota": "1/3", "nome": "Elena", "cognome": "Bianchi", "denominazione": null,
"codice_fiscale": "BNCLNA82H41H501Y", "partita_iva": null,
"dt_nascita": "1982-06-01", "comune_nascita": "Roma", "provincia_nascita": "RM", "sesso": "F"
},
"after": {
"quota": "1/2", "nome": "Elena", "cognome": "Bianchi", "denominazione": null,
"codice_fiscale": "BNCLNA82H41H501Y", "partita_iva": null,
"dt_nascita": "1982-06-01", "comune_nascita": "Roma", "provincia_nascita": "RM", "sesso": "F"
}
}
]
}
}
]
}Ogni elemento di added / removed (e i blocchi before / after di modified) riporta i dati anagrafici base del soggetto: quota, nome, cognome, denominazione (persona fisica → nome+cognome, azienda → denominazione), codice_fiscale, partita_iva, dt_nascita, comune_nascita, provincia_nascita, sesso. I campi non disponibili sono null. Il codice_fiscale è anche incapsulato nell'id di modified (prefisso CF:, oppure PI: per la P.IVA o NM: se manca l'identificativo fiscale).
NOTE
Il webhook parte in automatico dal cron di monitoraggio, con retry in caso di errori di rete. Rispondi 2xx per confermare la ricezione.
TIP
Il webhook_url è opzionale in fase di creazione: se non lo passi non viene inviato nulla. Puoi aggiungerlo o cambiarlo in un secondo momento (vedi sotto).
Provare il webhook in **sandbox** (staging)
Sull'ambiente di test (https://api-dev.dokicasa.it) non devi aspettare un cambio proprietari reale:
- Alla creazione, se passi un
webhook_url, inviamo subito un eventoimmobile.owners_changedd'esempio a quell'URL (la risposta della create includesimulated_webhook_sent: true). - Puoi re-inviarlo quando vuoi con
POST /api/user-monitorings/{id}/simulate-webhook.
Il payload ha lo stesso identico formato dell'evento reale: punta webhook_url a un inspector (webhook.site) per vederlo arrivare. In produzione questi automatismi sono disattivati — il webhook parte solo su un cambio proprietari reale.
Elenco dei monitoraggi
GET /api/users/me/monitorings — ritorna i tuoi monitoraggi (paginati). Filtri via query string:
| Parametro | Valori | Note |
|---|---|---|
filter.type | IMMOBILE (default) / SOGGETTO | tipo di monitoraggio |
filter.status | ACTIVE, EXPIRED, CANCELLED | anche multipli, separati da virgola |
filter.source | API / CENSIMENTO | origine del monitoraggio |
filter.change_owner | 1 | solo quelli con variazioni proprietari |
filter.text | testo libero | cerca in note + indirizzo/dati catastali |
sort_ends_at | ASC / DESC | ordina per scadenza (default: id DESC) |
page | numero | pagina (risposta paginata) |
Se ti servono solo gli id: GET /api/users/me/monitorings-ids.
NOTE
È un endpoint di sola lettura: funziona sempre col tuo Bearer token, anche senza whitelist origin configurata. Il default filter.type=IMMOBILE ritorna solo i monitoraggi immobile — per i soggetti passa filter.type=SOGGETTO.
Gestione del monitoraggio
| Metodo | Path | Cosa fa |
|---|---|---|
GET | /api/user-monitorings/{id} | Dettaglio del monitoraggio: dati del monitoring, immobile collegato (model), proprietari attuali (model.soggetti), eventi di variazione (events) e storico letture proprietari (proprietari_history). Vedi esempio sotto. |
PATCH | /api/user-monitorings/{id}/webhook | Imposta o rimuove (passando null) la webhook_url. Body: { "webhook_url": "https://…" }. |
PATCH | /api/user-monitorings/{id} | Cambia lo status: ACTIVE (attivo), DISACTIVE (in pausa), CANCELED (annullato). |
POST | /api/user-monitorings/{id}/renew | Rinnova il monitoraggio. |
POST | /api/user-monitorings/{id}/simulate-webhook | Solo sandbox: invia subito al webhook_url un evento immobile.owners_changed di esempio, per provare la ricezione senza attendere un cambio reale. In produzione risponde 404. |
DELETE | /api/user-monitorings/{id} | Elimina il monitoraggio. |
Esempio risposta — dettaglio monitoraggio
{
"id": 6004,
"user_id": 5101,
"status": "ACTIVE",
"ends_at": "2026-07-10 11:08:01",
"model_type": "App\\Models\\ScannerImmobile",
"model_id": 2013602,
"model": {
"id": 2013602,
"comune": "Nardo'", "provincia": "LE",
"foglio": "129", "particella": "1474", "subalterno": "1",
"categoria": "A03",
"indirizzo_completo": "VIA CAVALIERI TEUTONICI n. 6 Piano T",
"soggetti": [
{
"denominazione": "COLELLA ANNA MARIA",
"codice_fiscale": "CLLNMR35P44F842Z",
"pivot": { "quota": "1/2", "titolarita": "Proprieta'" }
}
]
},
"events": [
{
"date": "2025-12-02",
"differences": {
"added": [ { "quota": "1/2", "denominazione": "BERNES ANGELO" } ],
"removed": [ { "quota": "", "denominazione": "AMATEIS DAVIDE" } ],
"modified": []
}
}
],
"proprietari_history": [
{
"date": "2025-11-02",
"read_at": "2025-11-02 00:00:00",
"scanner_request_id": 2071196,
"proprietari": [
{ "denominazione": "AMATEIS DAVIDE", "codice_fiscale": "MTSDVD82H03D208H", "quota": "", "titolarita": "" },
{ "denominazione": "COLELLA ANNA MARIA", "codice_fiscale": "CLLNMR35P44F842Z", "quota": "1/2", "titolarita": "Proprieta'" }
]
},
{
"date": "2025-12-02",
"read_at": "2025-12-02 00:00:00",
"scanner_request_id": 2241215,
"proprietari": [
{ "denominazione": "BERNES ANGELO", "quota": "1/2", "titolarita": "Proprieta'" },
{ "denominazione": "COLELLA ANNA MARIA", "quota": "1/2", "titolarita": "Proprieta'" }
]
}
]
}| Campo | Cosa contiene |
|---|---|
model | Dettaglio dell'immobile monitorato (comune, foglio/particella/sub, categoria, indirizzo…) |
model.soggetti | Proprietari attuali (con quota e titolarità nel pivot) |
events | Variazioni proprietari: diff per data (added / removed / modified) |
proprietari_history | Snapshot dei proprietari a ogni lettura (una entry per scanner_request, con date/read_at): la storia grezza, non deduplicata, di com'erano i proprietari ad ogni controllo |
Caso d'uso: ricerca da indirizzo
Hai un indirizzo e vuoi gli immobili al catasto associati. Flusso in 2 fasi: risoluzione indirizzo → immobili.
list-addresses(risoluzione indirizzo) —POST /api/scanner/list-addresses. Attendi via socket/webhook/polling. La lista degli indirizzi normalizzati è già nel camporesultsdella risposta diGET /api/scanner-request/{id}— non serve chiamare/results.- Immobili da indirizzo — usa un indirizzo del passo 1 come
address_valuenella chiamata di scanner immobili (endpoint preciso su Swagger, sezione Scanner). - Recupero risultati — quando arriva
SUCCESS, chiamaGET /api/scanner-request/{id}/resultsper la lista immobili.
Caso d'uso: visure, ispezioni, note, mappe (PDF)
Tutte le richieste che producono un PDF (visura catastale, ispezione, nota, mappa) seguono lo stesso pattern.
- Crei la richiesta —
POST /api/scanner/{type}(il tipo dipende dal documento, vedi Swagger). - Attendi il completamento — via WebSocket o webhook: lo stato passa per
ENQUEUED→SCANNINGfino aSUCCESSoERROR. - Retry automatico su errori transient — se durante l'elaborazione c'è un errore temporaneo (linea con i servizi esterni), il sistema riprova da solo ogni ~5 minuti. Non devi reinviare nulla. Il credito viene scalato solo al primo esito positivo.
- Ottieni il PDF — il file è restituito direttamente nella risposta di
GET /api/scanner-request/{id}(non serve/results). In più il PDF viene inviato automaticamente via email all'indirizzo associato al token, quindi l'utente finale lo riceve comunque anche senza integrare il download lato client.
Polling — solo come ultima opzione
Sconsigliato
Hai due meccanismi push (WebSocket e webhook) che eliminano la necessità di polling. Valutali prima: il polling aumenta latenza e carico server senza vantaggi reali.
Se proprio devi pollare, interroga periodicamente:
GET /api/scanner-request/{id}Linee guida pratiche:
- Intervallo minimo consigliato: 3 secondi tra una chiamata e l'altra.
- Backoff esponenziale dopo qualche tentativo (es. 3s → 6s → 12s).
- Limite di tentativi sensato (es. 5 minuti totali), poi timeout lato tuo.
- Interrompi appena lo stato è
SUCCESSoERROR.
Risposta tipica:
{ "id": 12345, "status": "SCANNING", "percentage": 42 }Note operative
- Conserva sempre l'
id(scanner_request_id) restituito alla creazione: serve per ogni operazione successiva. - Gestisci esplicitamente lo stato
ERROR: leggi il messaggio per capire la causa. - Non condividere mai il token API: trattalo come una password.
- In produzione, preferisci webhook o socket al polling.