API VIISI
La guida per chi integra
Collegare un gestionale, un badge system o un cruscotto aziendale a VIISI: leggere chi risulta dentro, scaricare le visite di un periodo, ricevere un messaggio quando qualcuno entra. Senza usare la password di nessuno.
In tre minuti
Tre passi: si crea una chiave dal portale, la si mette in un'intestazione, si chiama. Non c'è un flusso di autorizzazione da implementare, e non serve registrare un'applicazione da nessuna parte.
1. La chiave
Nel portale, con un utente amministratore: Configurazione → Integrazioni → Nuova chiave. Si dà un nome — quello del programma che la userà — e si spuntano i permessi che servono.
2. L'indirizzo
https://viisi.ak8.cloud/v1/api
3. La prima chiamata
Richiesta
curl -H "Authorization: Bearer viisi_..." \
https://viisi.ak8.cloud/v1/api/pubblica/presenti
Risposta
[
{
"codice_visita": "V-2609-0007",
"tipologia": "visitatore",
"motivo": "Riunione commerciale",
"ingresso_effettivo": "2026-09-02T08:41:12.204Z",
"nome": "Mario",
"cognome": "Rossi",
"azienda": "Meccanica Rossi Snc",
"sede": "Stabilimento di Prato",
"referente": "Marco Bianchi"
}
]
Tutto quello che segue sono dettagli di questo. Le risposte sono JSON, le
date sono in UTC in formato ISO 8601, e i campi che non hanno un valore
arrivano a null invece di sparire.
La chiave
È una stringa lunga che comincia per viisi_, si presenta in
Authorization: Bearer, e non scade da sola a meno che non le
si dia una data.
Perché non è un token OAuth
Un token firmato si verifica senza interrogare il database, ed è il motivo per cui i token di sessione di VIISI durano quindici minuti: finché non scadono, valgono. Una credenziale che deve restare in un gestionale per un anno non può funzionare così — revocarla richiederebbe una lista di token annullati da consultare a ogni richiesta, cioè esattamente la query che il token firmato serviva a evitare.
Quindi la chiave è una stringa casuale che verifichiamo interrogando il database ogni volta. Il prezzo è una query in più; quello che si compra è che la revoca ha effetto sulla richiesta successiva, non allo scadere di qualcosa.
Dove conservarla
- In una variabile d'ambiente o nella configurazione del server, non nel codice sorgente.
- Mai in una pagina web o in un'app che gira sul dispositivo di qualcuno: chiunque apra gli strumenti del browser la legge.
- Una chiave per programma, non una per tutti: così si revoca quella giusta senza fermare gli altri.
Revocarla
Dal portale, in Configurazione → Integrazioni: dall'API
una chiave non si revoca. Una chiave revocata riceve 401 dalla
chiamata dopo, comprese quelle già in volo che non hanno ancora raggiunto
il server.
Nell'elenco delle chiavi si vede l'ultimo uso: serve a capire se una chiave che nessuno ricorda è ancora collegata a qualcosa prima di toglierla.
Gli ambiti
Il perimetro si dichiara alla creazione e non si allarga dopo. Una chiave nata per leggere le presenze non deve poter creare una visita perché un domani qualcuno ha aggiunto un permesso da qualche parte.
| Ambito | Permette |
|---|---|
presenze:leggi | Chi risulta dentro adesso |
visite:leggi | Le visite di un periodo |
visitatori:leggi | Cercare una persona in rubrica |
referenti:leggi | L'elenco di chi riceve visite |
imprese:leggi | Le imprese fornitrici censite |
documenti:leggi | Cosa manca e cosa sta per scadere |
documenti:scrivi | Registrare una carta e la sua validità |
visite:scrivi | Creare e modificare visite (in arrivo) |
imprese:scrivi | Modificare l'anagrafica delle imprese (in arrivo) |
webhook:gestisci | Registrare e togliere indirizzi di consegna |
/pubblica
Le rotte che servono il portale non si aprono alle chiavi, nemmeno a una
che ha tutti gli ambiti: rispondono 403. Se lo facessero, ogni
funzione aggiunta domani al prodotto diventerebbe pubblica senza che
nessuno l'abbia deciso — e un'API pubblica è una promessa che si mantiene
per anni.
Le rotte
Sono poche di proposito. Ogni rotta è una promessa, e le promesse in più si pagano quando bisogna mantenerle mentre il prodotto cambia.
Chi risulta dentro adesso, cioè le visite con l'ingresso registrato e ancora aperte, in ordine di ingresso. È la rotta che serve al cruscotto della portineria. L'elenco vale quanto le uscite registrate, e i dipendenti non ci sono.
Richiesta
curl -H "Authorization: Bearer $VIISI_KEY" \
$API/pubblica/presenti
Campi
codice_visita, tipologia, motivo,
ingresso_effettivo,
nome, cognome, azienda,
sede, referente
Le visite di un periodo. Senza parametri restituisce quelle di oggi; con
dal e al quelle dell'intervallo, al massimo
cinquecento per volta, dalla più recente.
Richiesta
curl -H "Authorization: Bearer $VIISI_KEY" \
"$API/pubblica/visite?dal=2026-09-01&al=2026-09-30"
Campi
codice_visita, tipologia, stato, motivo,
data_prevista, ingresso_effettivo,
uscita_effettiva,
nome, cognome, email, azienda,
sede, referente
Le date si scrivono 2026-09-01 oppure per intero
2026-09-01T06:00:00Z. Il filtro guarda l'ingresso vero quando
c'è, altrimenti la data prevista: una visita programmata e mai arrivata
resta nel giorno in cui era attesa.
stato segue il ciclo della visita:
| Stato | Vuol dire |
|---|---|
programmata | In agenda, l'invito non è ancora partito |
invitata | L'invito è stato mandato al visitatore |
in_attesa | Arrivato al chiosco, aspetta l'assenso del referente |
autorizzata | Il referente ha detto sì, la persona non è ancora entrata |
presente | È dentro |
uscita | Check-out fatto dalla persona |
chiusa_ufficio | Chiusa d'ufficio dopo le ore scelte per la sede (12 di serie), perché nessuno ha registrato l'uscita |
rifiutata | Il referente ha negato l'accesso |
annullata | Disdetta prima dell'arrivo |
scaduta | La finestra prevista è passata senza check-in |
no_show | Attesa e mai arrivata |
in_attesa, autorizzata e
rifiutata oggi non compaiono: il vostro programma li tratti
comunque, perché sono valori previsti.
uscita è la persona che ha timbrato; chiusa_ufficio
è il sistema che chiude, dopo le ore scelte per la sede, chi se n'è andato
senza dirlo.
Chi calcola le presenze dovrebbe contarle entrambe come uscite, e chi
misura la qualità del dato dovrebbe tenerle separate.
Chi in azienda può ricevere visite, con la sede di appartenenza. Serve a chi deve popolare una tendina nel proprio programma, o a chi sincronizza l'anagrafica dal gestionale del personale.
Richiesta
curl -H "Authorization: Bearer $VIISI_KEY" \
$API/pubblica/referenti
Risposta
[
{
"id": "fd03ddb7-…",
"nome": "Marco",
"cognome": "Bianchi",
"email": "m.bianchi@…",
"id_esterno": null,
"sede": "Prato"
}
]
id_esterno: il campo che serve a voi
È lo spazio per l'identificativo che quella stessa persona ha nel
vostro sistema. Accoppiare per nome e cognome funziona finché non
ci sono due Mario Rossi; per email finché nessuno cambia indirizzo — e
l'email di un dipendente cambia più spesso di quanto si creda.
Si valorizza con l'importazione dei referenti, passandolo insieme agli altri campi:
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"referenti":[
{"nome":"Marco","cognome":"Bianchi",
"email":"m.bianchi@example.it","id_esterno":"HR-4471"}
]}' \
$API/referenti/import
La prima volta aggancia, dalla seconda comanda. L'importazione cerca per identificativo e per email insieme, preferendo il primo: così l'esportazione che porta gli identificativi per la prima volta riconosce la rubrica che c'è già invece di ricrearla, e da lì in poi un cambio di indirizzo aggiorna la persona giusta invece di sdoppiarla.
Sul visitatore id_esterno per ora si legge soltanto: arriverà
in scrittura insieme a visite:scrivi, che è il momento in cui
un gestionale avrà una visita da creare e una persona da accoppiare.
Cerca una persona in rubrica per nome, cognome, email o azienda. Servono
almeno due caratteri in testo, e tornano al
massimo cento risultati.
Richiesta
curl -H "Authorization: Bearer $VIISI_KEY" \
"$API/pubblica/visitatori?testo=rossi"
Risposta
[
{
"id": "b255ced5-…",
"nome": "Mario",
"cognome": "Rossi",
"email": "mario.rossi@example.it",
"telefono": null,
"id_esterno": null,
"azienda": "Meccanica Rossi Snc",
"visite": 1
}
]
testo la risposta è un elenco vuoto, non l'anagrafica
intera. Un'integrazione che deve trovare una persona non ha bisogno di
scaricarle tutte, e un'API che lo permette diventa il modo più comodo di
portarsi via una rubrica. Chi ha bisogno dell'esportazione completa la fa
dal portale, dove resta scritto chi l'ha fatta e quando.
Le persone anonimizzate — per scadenza della conservazione o per richiesta di cancellazione — non compaiono.
Imprese e documenti
Chi fa lavori dentro un'azienda deve avere le carte in ordine: il DURC
dell'impresa, la formazione dei suoi tecnici, l'idoneità sanitaria. VIISI
tiene le scadenze e le mostra nello scadenzario. Ai tornelli collegati con
/pubblica/abilitazione risponde no se le carte non sono in
regola. Il chiosco oggi non ferma nessuno (vedi
Funzioni, «da attivare»). Se
quelle date le tenete già in un gestionale documentale, queste rotte
servono a non scriverle due volte.
Le imprese fornitrici, con il loro stato di fornitura — attivo,
in_pausa, cessato — e il vostro
id_esterno, che è come le ritrovate.
Cosa manca e cosa sta per scadere, entro ?giorni= (trenta di
default). Include i documenti mai consegnati, non solo
quelli in scadenza: un obbligo che nessuno ha mai caricato è più grave di
uno che scade fra due settimane, e un elenco di sole scadenze non lo
mostrerebbe mai.
Richiesta
curl -H "Authorization: Bearer $VIISI_KEY" \
"$API/pubblica/scadenzario?giorni=60"
Risposta
[
{
"ambito": "impresa",
"azienda": "Impianti Verdi Srl",
"persona": null,
"tipo": "DURC",
"chiave_tipo": "durc",
"obbligatorio": true,
"valido_al": "2026-09-18",
"giorni": 15,
"situazione": "in_scadenza"
}
]
situazione vale mancante, scaduto,
in_scadenza o respinto. Le imprese in pausa o
cessate non compaiono: chiedere il rinnovo a chi ha finito il lavoro è il
modo più rapido di far ignorare i propri messaggi.
Registra una carta e fino a quando vale. Si indirizza con i vostri identificativi, non con i nostri:
curl -X POST -H "Authorization: Bearer $VIISI_KEY" \
-H "Content-Type: application/json" \
-d '{"tipo":"durc",
"impresa_id_esterno":"FORN-4471",
"riferimento":"INAIL_31554702",
"rilasciato_il":"2026-08-20",
"valido_al":"2026-12-18"}' \
$API/pubblica/documenti
tipo è la chiave del catalogo — durc,
visura_camerale, formazione_generale,
idoneita_sanitaria e le altre, visibili dal portale in
Configurazione → Documenti fornitori. Per un documento
personale si usa persona_id_esterno invece di
impresa_id_esterno.
Il PDF si allega in base64 nel campo file, ed è facoltativo:
la scadenza da sola basta a tenere aggiornati lo scadenzario e la risposta
di /pubblica/abilitazione. Le richieste ai fornitori partono a
mano dal portale.
Se il documento lo tenete già nel vostro archivio — SharePoint, un drive,
il gestionale delle qualifiche — potete mandarne
l'indirizzo invece del file, nel campo
collegamento. Serve a non avere due copie della stessa carta:
al primo rinnovo fatto da una parte sola, una delle due diventa quella
sbagliata e nessuno sa quale.
curl -X POST -H "Authorization: Bearer $VIISI_KEY" -H "Content-Type: application/json" -d '{"tipo":"durc",
"impresa_id_esterno":"FORN-4471",
"valido_al":"2026-12-18",
"collegamento":"https://archivio.esempio.it/durc/4471.pdf"}' $API/pubblica/documenti
Tre regole, e la risposta dice quale delle due strade avete preso con
"conservato" e "collegato":
- O il file o il collegamento, non tutti e due.
- Solo
https://: punta al documento di una persona, e un indirizzo in chiaro si intercetta come qualunque altra cosa. - Non per i tipi che non conservano il file — vedi qui sotto: un collegamento sarebbe il modo di rimettere dentro dalla finestra quello che si è deciso di non tenere.
"conservato": false.
Caricare di nuovo lo stesso tipo per la stessa impresa o persona sostituisce: la versione precedente resta negli archivi ma esce dagli elenchi. È il rinnovo, e non serve cancellare prima.
Tornelli e lettori di badge
Una domanda sola: questo badge apre? Chi vende controllo accessi ha già i lettori e il software; quello che gli manca è la risposta.
Richiesta
curl -X POST -H "Authorization: Bearer $VIISI_KEY" \
-H "Content-Type: application/json" \
-d '{"credenziale":"04:A2:BF:19"}' \
$API/pubblica/abilitazione
Risposta
{
"riconosciuta": true,
"abilitata": false,
"motivo": "Documenti non in regola",
"nome": "Franco Verdi",
"azienda": "Impianti Verdi Srl",
"ostacoli": [
{ "tipo": "DURC",
"situazione": "scaduto",
"motivo": "DURC: scaduto il 28/08/2026" }
]
}
200, anche quando la risposta è «non abilitato».
Un 403 manderebbe l'integrazione a cercare un guasto in sé
stessa, quando invece ha funzionato tutto.
È una POST benché non cambi niente, e la ragione è che
il codice di un tesserino non deve finire in un indirizzo:
gli indirizzi si scrivono nei log di ogni proxy attraversato, e un UID
letto da lì è un tesserino clonabile.
L'UID si può mandare come lo legge il lettore — 04:A2:BF:19,
04a2bf19, 04-A2-BF-19: separatori e maiuscole
non contano. Lo stesso tag letto da due marche di lettore arriva scritto
in due modi, e senza normalizzazione sarebbero due credenziali diverse.
Le ragioni di un no
motivo | Cosa è successo |
|---|---|
| Credenziale non riconosciuta | Il codice non risulta. Non si dice altro: a un lettore non serve, e a chi prova a indovinare servirebbe |
| Credenziale revocata | Il badge è stato disattivato dal portale |
| Credenziale scaduta il … | Aveva una data di fine, ed è passata |
| Documenti non in regola | La persona c'è e il badge vale, ma le sue carte no: ostacoli dice quali |
| Persona non più in anagrafica | Anonimizzata o disattivata |
Gli errori
Sempre nella stessa forma, con il percorso e l'istante: bastano a ritrovare la richiesta nei nostri registri se ci si scrive.
{
"stato": 403,
"messaggio": "Alla chiave mancano gli ambiti: visite:leggi.",
"percorso": "/v1/api/pubblica/visite",
"istante": "2026-09-02T14:26:12.330Z"
}
| Codice | Vuol dire | Cosa fare |
|---|---|---|
401 |
Chiave assente, scaduta o revocata | Non ritentare: la chiave non tornerà buona da sola |
403 |
Ambito mancante, o rotta non aperta alle chiavi | Il messaggio dice quale ambito manca. Serve una chiave nuova: gli ambiti non si allargano |
429 |
Troppe richieste — il limite è 120 al minuto | Aspettare e riprovare. Se serve stabilmente di più, i webhook risolvono il problema alla radice |
403 |
Servizio sospeso — l'abbonamento del cliente non è in regola | Non riguarda l'integrazione: si sblocca quando il cliente rinnova o paga (per informazioni, info@viisi.it). L'API torna a rispondere da sola |
5xx |
Un problema nostro | Ritentare con attese crescenti. Se dura, scriveteci con l'istante |
I webhook
Si lascia un indirizzo HTTPS, e VIISI ci scrive quando succede qualcosa. Nessuna interrogazione ripetuta, nessun ritardo.
Si registrano dal portale — Configurazione → Integrazioni →
Webhook — oppure dall'API con l'ambito
webhook:gestisci:
curl -X POST -H "Authorization: Bearer $VIISI_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://gestionale.example/viisi",
"eventi":["visita.ingresso","visita.uscita"],
"descrizione":"Timbrature"}' \
$API/pubblica/webhook
Con la stessa chiave si elencano (GET), si sospendono
(PATCH con {"stato":"NA"}), si tolgono
(DELETE), e si leggono le ultime consegne con il loro esito:
GET /pubblica/webhook/{id}/consegne. È la rotta che evita la
telefonata — si vede da soli se il proprio endpoint ha risposto 500 o se
non è stato raggiunto affatto.
La risposta contiene il segreto con cui firmeremo le consegne. Come la chiave, si vede una volta sola.
https:// viene rifiutato alla registrazione.
Cosa si può ascoltare
| Evento | Quando |
|---|---|
visita.creata | Una visita entra in agenda, da chiunque sia stata inserita |
visita.ingresso | La persona ha fatto il check-in ed è dentro |
visita.uscita | Check-out registrato |
visita.autorizzata | Il referente ha dato l'assenso a chi era in attesa. Oggi non succede: tutti i percorsi entrano senza autorizzazione |
visita.rifiutata | Il referente ha negato l'accesso. Oggi non succede, per lo stesso motivo |
visita.invitata | È partito l'invito al visitatore (in arrivo) |
credenziale.rilasciata | Un badge o un codice è stato assegnato (in arrivo) |
credenziale.revocata | Un badge o un codice non vale più (in arrivo) |
documento.caricato | Un fornitore ha consegnato una carta (in arrivo) |
documento.in_scadenza | Un documento entra nel preavviso (in arrivo) |
documento.scaduto | Un documento ha superato la sua validità (in arrivo) |
visita.creata, visita.ingresso e
visita.uscita. Per i documenti, nel frattempo, c'è
GET /pubblica/scadenzario.
L'elenco degli eventi a cui ci si può iscrivere si può anche chiedere al
programma: GET /pubblica/eventi, con l'ambito
webhook:gestisci. Comprende anche quelli in arrivo.
Cosa arriva
Intestazioni
Content-Type: application/json
X-VIISI-Evento: visita.ingresso
X-VIISI-Istante: 1756822567
X-VIISI-Firma: sha256=9f2b…
X-VIISI-Consegna: 4c8a1f7e-…
User-Agent: VIISI-Webhook/1
Corpo
{
"evento": "visita.ingresso",
"istante": "2026-09-02T08:41:12.204Z",
"dati": {
"codice_visita": "V-2609-0007",
"stato": "presente",
"nome": "Mario",
"cognome": "Rossi",
"azienda": "Meccanica Rossi Snc",
"sede": "Prato",
"referente": "Marco Bianchi",
"id_esterno": null,
"id_esterno_referente": null
}
}
Il vostro endpoint deve rispondere 2xx, e in fretta: dopo dieci secondi chiudiamo e la consideriamo fallita. Se il lavoro è lungo, mettete in coda e rispondete subito — un endpoint lento non deve rallentare un check-in.
Verificare la firma
Il vostro indirizzo è raggiungibile da chiunque lo conosca. La firma è come distinguete una consegna nostra da una di qualcun altro, ed è l'unico controllo che conta davvero.
È un HMAC-SHA256 calcolato sulla stringa
istante + "." + corpo, con il segreto del webhook.
Il corpo è quello grezzo, byte per byte come è arrivato:
se lo si riserializza dopo averlo interpretato, uno spazio di differenza
cambia la firma e non torna più niente.
Node.js
const express = require('express');
const crypto = require('crypto');
const app = express();
// Il corpo grezzo, non l'oggetto: express.json() lo consumerebbe.
app.post('/viisi', express.raw({ type: 'application/json' }), (req, res) => {
const istante = req.headers['x-viisi-istante'];
const atteso = crypto
.createHmac('sha256', process.env.VIISI_SEGRETO)
.update(`${istante}.${req.body}`)
.digest('hex');
// timingSafeEqual e non !==: il confronto normale esce al primo
// carattere diverso, e quel tempo si misura.
const ricevuta = Buffer.from(req.headers['x-viisi-firma'] ?? '');
const calcolata = Buffer.from(`sha256=${atteso}`);
if (ricevuta.length !== calcolata.length ||
!crypto.timingSafeEqual(ricevuta, calcolata)) {
return res.sendStatus(401);
}
// Più di cinque minuti: è una consegna vecchia rimandata da qualcuno.
if (Math.abs(Date.now() / 1000 - Number(istante)) > 300) {
return res.sendStatus(401);
}
const fatto = JSON.parse(req.body);
// Rispondere subito, lavorare dopo.
res.sendStatus(200);
accoda(req.headers['x-viisi-consegna'], fatto);
});
Python
import hmac, hashlib, time
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/viisi")
def viisi():
istante = request.headers.get("X-VIISI-Istante", "")
corpo = request.get_data() # grezzo, non request.json
atteso = "sha256=" + hmac.new(
SEGRETO.encode(),
f"{istante}.".encode() + corpo,
hashlib.sha256,
).hexdigest()
# compare_digest e non ==: il tempo del confronto non deve dire nulla
if not hmac.compare_digest(atteso, request.headers.get("X-VIISI-Firma", "")):
abort(401)
if abs(time.time() - int(istante)) > 300:
abort(401)
fatto = request.get_json()
accoda(request.headers["X-VIISI-Consegna"], fatto)
return "", 200
PHP
<?php
// Il corpo grezzo: $_POST lo avrebbe già interpretato.
$corpo = file_get_contents('php://input');
$istante = $_SERVER['HTTP_X_VIISI_ISTANTE'] ?? '';
$firma = $_SERVER['HTTP_X_VIISI_FIRMA'] ?? '';
$atteso = 'sha256=' . hash_hmac('sha256', "$istante.$corpo", VIISI_SEGRETO);
// hash_equals e non ===: il confronto a tempo costante
if (!hash_equals($atteso, $firma) || abs(time() - (int)$istante) > 300) {
http_response_code(401);
exit;
}
$fatto = json_decode($corpo, true);
http_response_code(200);
// il lavoro vero dopo aver risposto
accoda($_SERVER['HTTP_X_VIISI_CONSEGNA'], $fatto);
C#
// ASP.NET Core — minimal API
app.MapPost("/viisi", async (HttpRequest req) =>
{
using var lettore = new StreamReader(req.Body);
var corpo = await lettore.ReadToEndAsync(); // grezzo
var istante = req.Headers["X-VIISI-Istante"].ToString();
var firma = req.Headers["X-VIISI-Firma"].ToString();
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(Segreto));
var calcolata = "sha256=" + Convert.ToHexString(
hmac.ComputeHash(Encoding.UTF8.GetBytes($"{istante}.{corpo}"))).ToLowerInvariant();
if (!CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(calcolata), Encoding.UTF8.GetBytes(firma)))
return Results.Unauthorized();
var eta = Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(istante));
if (eta > 300) return Results.Unauthorized();
Accoda(req.Headers["X-VIISI-Consegna"], JsonDocument.Parse(corpo));
return Results.Ok();
});
Ritentativi, doppioni, sospensione
Cosa succede quando il vostro endpoint non risponde, e cosa dovete fare perché non ne nascano guai.
Cinque tentativi
Una consegna che fallisce viene rimandata dopo 1, 5, 15 e 60 minuti. Un endpoint che risponde male durante un aggiornamento non deve far perdere gli ingressi di quei minuti.
Lo stesso fatto può arrivare due volte
Se rispondete 200 ma la risposta si perde per strada, per noi
è un fallimento e ritentiamo. Per questo ogni consegna porta
X-VIISI-Consegna, che non cambia fra un tentativo e
l'altro: tenete gli identificativi già trattati e scartate i
ripetuti.
Un indirizzo morto si sospende
Dopo venti fallimenti di fila l'indirizzo passa in stato sospeso e smettiamo di scrivergli. Non è una punizione: una coda che cresce senza fine per un endpoint spento rallenta le consegne di tutti gli altri. Si riattiva dal portale, e il conteggio riparte da zero.
Come si vede cosa è successo
Nel portale, per ogni indirizzo, ci sono le ultime consegne con il loro esito: codice HTTP, errore di rete, numero di tentativi. Un 500 dal vostro endpoint e un nome DNS che non si risolve si vedono diversi, ed è quello che evita che la conversazione cominci con «da noi funziona».
L'ordine non è garantito
Due fatti vicini possono arrivare invertiti — un ingresso e un'uscita a
pochi secondi, con il primo tentativo fallito. Se l'ordine conta, guardate
istante nel corpo, che è il momento del fatto e non quello
della consegna.
Cosa promettiamo
Un'integrazione scritta oggi deve funzionare fra due anni senza che nessuno la tocchi. Ecco cosa promettiamo e cosa no.
- I campi che ci sono restano. Possiamo aggiungerne di nuovi — il vostro programma deve ignorare quelli che non conosce — ma non togliamo né rinominiamo quelli documentati qui.
-
I valori chiusi possono allungarsi. Un
statoo uneventonuovo può comparire: trattate l'ignoto senza rompervi, non con un errore. -
Il prefisso
/v1/non cambia significato. Se un giorno servisse un cambiamento che rompe, sarà/v2/, e la/v1/resterà per almeno dodici mesi. -
Le rotte del portale non sono un'API. Cambiano quando
cambia l'interfaccia, senza preavviso. Se vi serve qualcosa che non è
sotto
/pubblica, chiedetecelo: aggiungerlo qui è il modo per non trovarselo rotto.
Domande frequenti
La chiave vede tutte le sedi?
Sì: è una chiave dell'azienda, non di una sede. Il campo
sede è in ogni risposta, e si filtra dalla vostra parte.
Posso creare una visita dall'API?
Non ancora. L'ambito visite:scrivi esiste già ed è il posto
dove arriverà. Nel frattempo, per far programmare le visite da un
assistente — Claude o altri — c'è il collegamento MCP, descritto nel
manuale. Il programma di collegamento per ora ve
lo mandiamo noi, su richiesta ad
assistenza@viisi.it, e usa le
credenziali del portale di chi lo installa.
Quanto tempo restano i dati?
I tempi sono gli stessi per tutti, e valgono anche per l'API: se una
persona non torna da 24 mesi, nome, recapiti, targa, foto, note e codice
fiscale si cancellano (le visite restano, senza questi dati: in
/pubblica/visite il nome diventa «Anonimizzato»); le foto si
cancellano dopo 7
giorni, salvo quelle dei tesserini permanenti ancora validi. Se il cliente
ha bisogno di tempi diversi, li impostiamo noi su sua richiesta. Se il
vostro programma deve tenere uno storico con i nomi più a lungo, deve
conservarlo lui, e il cliente deve saperlo.
C'è un ambiente di prova?
I trenta giorni di prova sono un'azienda vera con dati vostri: è lì che si collauda un'integrazione, senza toccare quella di produzione. Chi ha già un abbonamento può chiederci una seconda azienda per le prove.
Come vi segnalo un problema?
A assistenza@viisi.it, con
l'istante preso dalla risposta d'errore o dalla consegna: con
quello ritroviamo la richiesta esatta nei registri.