API di analisi in sola lettura
L’API HTTP api.jonot.io/v1/* fornisce accesso in sola lettura ai dati di biglietti e code della tua organizzazione — nessun accesso Admin richiesto, solo un bearer token. Usala per trasferire dati in un data warehouse, uno strumento BI o una dashboard personalizzata.
Ottenere un token
Sezione intitolata “Ottenere un token”- Apri admin.jonot.io/settings/integrations.
- Fai clic sulla scheda API tokens.
- Fai clic su Create token, dagli un nome (es. “Power BI”) e conferma.
- Copia immediatamente il token — viene mostrato una sola volta e non può essere recuperato. Se lo perdi, revocalo e creane uno nuovo.
I token hanno il prefisso jot_ e non scadono mai da soli; revocali dalla stessa scheda quando non sono più necessari.
Autenticazione
Sezione intitolata “Autenticazione”Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| Stato | Significato |
|---|---|
401 | Token mancante, malformato, sconosciuto o revocato. |
402 | Token valido, ma l’organizzazione non ha la funzione API abilitata. |
429 | Limite di frequenza superato — vedi Limiti di frequenza sotto. |
400 | Parametri di query non validi, oppure un intervallo di date superiore a 90 giorni. |
Endpoint
Sezione intitolata “Endpoint”GET /v1/queues
Sezione intitolata “GET /v1/queues”Restituisce le sedi e le code della tua organizzazione, non filtrate e non paginate:
curl https://api.jonot.io/v1/queues \ -H "Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{ "locations": [ { "id": "loc_…", "name": "Downtown", "slug": "downtown", "queues": [ { "id": "q_…", "name": "Main Queue", "slug": "main-queue", "status": "ACTIVE" } ] } ]}Usa i valori id restituiti per filtrare /v1/tickets e l’esportazione CSV per queueId / locationId.
GET /v1/tickets
Sezione intitolata “GET /v1/tickets”Lettura paginata dei biglietti, limitata alla tua organizzazione.
| Parametro | Obbligatorio | Ripetibile | Note |
|---|---|---|---|
from | sì | no | ISO-8601, limite inferiore incluso su createdAt. |
to | sì | no | ISO-8601, limite superiore escluso. Intervallo massimo di 90 giorni. |
queueId | no | sì | Ripeti il parametro per filtrare più code. |
locationId | no | sì | Ripeti il parametro per filtrare più sedi. |
status | no | sì | Uno tra WAITING, CALLED, COMPLETED, CANCELED, SKIPPED, NO_SHOW. |
cursor | no | no | Valore opaco da nextCursor della pagina precedente. |
limit | no | no | Predefinito 100, massimo 500. |
curl "https://api.jonot.io/v1/tickets?from=2026-06-01T00:00:00Z&to=2026-06-08T00:00:00Z&status=COMPLETED" \ -H "Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{ "items": [ { "id": "tkt_…", "number": 42, "queueId": "q_…", "locationId": "loc_…", "status": "COMPLETED", "createdAt": "2026-06-01T09:14:02.000Z", "calledAt": "2026-06-01T09:20:11.000Z", "completedAt": "2026-06-01T09:24:47.000Z", "cancelledAt": null, "skippedAt": null, "noShowAt": null, "calledByDeviceSessionId": "dev_…" } ], "nextCursor": "eyJjcmVhdGVkQXQi…"}Le righe non includono mai l’hash bearer del biglietto né alcun dato personale inserito dal cliente (nome, note, dimensione del gruppo) — solo id, stato e i timestamp del ciclo di vita.
Paginazione: quando nextCursor non è nullo, passalo come cursor nella richiesta successiva per continuare da dove eri arrivato (stessi from/to/filtri). Un nextCursor null significa che hai raggiunto la fine dell’intervallo.
GET /v1/exports/tickets.csv
Sezione intitolata “GET /v1/exports/tickets.csv”Stessi filtri di /v1/tickets (from/to obbligatori, queueId/locationId/status ripetibili) meno cursor/limit — l’intero intervallo corrispondente viene trasmesso come un’unica risposta CSV, così non c’è un limite di 500 righe per pagina da aggirare per un prelievo massivo.
L’ordine delle colonne è stabile, ma analizza le colonne per nome di intestazione anziché per posizione fissa. La riga di intestazione è sempre presente e corrisponde esattamente a questo elenco:
id,number,queueId,locationId,status,createdAt,calledAt,completedAt,cancelledAt,skippedAt,noShowAt,calledByDeviceSessionIdcurl "https://api.jonot.io/v1/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z" \ -H "Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -o tickets.csvLa risposta viene trasmessa in streaming (Transfer-Encoding: chunked), così un’esportazione di 90 giorni/100.000 righe non deve essere bufferizzata in memoria su nessuno dei due lati — inviala direttamente a un file o a un parser.
Limite di intervallo di 90 giorni
Sezione intitolata “Limite di intervallo di 90 giorni”Ogni endpoint che accetta from/to rifiuta un intervallo superiore a 90 giorni con 400. Preleva i dati in modo incrementale (ad es. una chiamata a settimana) se hai bisogno di una cronologia più lunga — i timestamp del ciclo di vita del biglietto (calledAt, completedAt, …) ti permettono di ricostruire le durate di attesa/servizio senza recuperare di nuovo le stesse righe.
Limiti di frequenza
Sezione intitolata “Limiti di frequenza”60 richieste al minuto per token (non per IP — il budget viaggia con il token). Ogni risposta porta:
X-RateLimit-Remaining: 42X-RateLimit-Reset: 1751328000000Un 429 porta inoltre Retry-After (in secondi). Attendi quella finestra e riprova; una sincronizzazione pianificata ogni pochi minuti resta comodamente sotto il limite.
Python + pandas
Sezione intitolata “Python + pandas”import requestsimport pandas as pd
TOKEN = "jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"BASE = "https://api.jonot.io/v1"HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def fetch_tickets(frm: str, to: str) -> pd.DataFrame: rows = [] cursor = None while True: params = {"from": frm, "to": to, "limit": 500} if cursor: params["cursor"] = cursor res = requests.get(f"{BASE}/tickets", headers=HEADERS, params=params, timeout=30) res.raise_for_status() body = res.json() rows.extend(body["items"]) cursor = body["nextCursor"] if not cursor: break return pd.DataFrame(rows)
df = fetch_tickets("2026-06-01T00:00:00Z", "2026-07-01T00:00:00Z")df["waitSeconds"] = ( pd.to_datetime(df["calledAt"]) - pd.to_datetime(df["createdAt"])).dt.total_seconds()print(df.groupby("queueId")["waitSeconds"].mean())Oppure leggi direttamente l’esportazione CSV — pandas gestisce la risposta in streaming in modo trasparente:
df = pd.read_csv( f"{BASE}/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z", storage_options={"Authorization": f"Bearer {TOKEN}"},)Power BI (connettore Web)
Sezione intitolata “Power BI (connettore Web)”- In Power BI Desktop: Get Data → Web.
- Scegli Advanced e costruisci l’URL con il tuo intervallo di date, es.
https://api.jonot.io/v1/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z. - Sotto HTTP request header parameters, aggiungi un header chiamato
Authorizationcon il valoreBearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. - Fai clic su OK — Power BI rileva il CSV e apre l’anteprima della tabella.
- Fai clic su Load (oppure prima su Transform Data se vuoi impostare i tipi di colonna —
createdAt/calledAt/ecc. vengono importati come testo; convertili inDate/Timein Power Query). - Imposta un aggiornamento pianificato nel servizio Power BI se prelevi dati con una cadenza regolare; mantieni l’intervallo comodamente sotto i 90 giorni per aggiornamento.