Ga naar inhoud

Alleen-lezen analytics-API

De HTTP-API api.jonot.io/v1/* geeft alleen-lezentoegang tot de ticket- en wachtrijgegevens van je organisatie. Meld je aan met een bearer-token in plaats van een Admin-account. Gebruik de API om gegevens in een datawarehouse, Business Intelligence-tool of aangepast dashboard te importeren.

  1. Open admin.jonot.io/settings/integrations.
  2. Klik op het tabblad API tokens.
  3. Klik op Create token, geef het een naam (bijv. “Power BI”) en bevestig.
  4. Kopieer het token onmiddellijk — het wordt slechts één keer getoond en kan niet worden hersteld. Als je het kwijtraakt, trek je het in en maak je een nieuwe aan.

Tokens beginnen met het voorvoegsel jot_ en verlopen niet vanzelf; trek ze in vanaf hetzelfde tabblad wanneer ze niet meer nodig zijn.

Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
StatusBetekenis
401Ontbrekend, misvormd, onbekend of ingetrokken token.
402Geldig token, maar de organisatie heeft de API-functie niet ingeschakeld.
429Snelheidslimiet overschreden — zie Snelheidslimieten hieronder.
400Ongeldige queryparameters, of een datumbereik van meer dan 90 dagen.

Geeft de locaties en wachtrijen van je organisatie terug, ongefilterd en niet gepagineerd:

Terminal window
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"
}
]
}
]
}

Gebruik de teruggegeven id-waarden om /v1/tickets en de CSV-export te filteren op queueId / locationId.

Gepagineerde ticketlezing, beperkt tot je organisatie.

ParameterVerplichtHerhaalbaarOpmerkingen
fromjaneeISO-8601, inclusieve ondergrens op createdAt.
tojaneeISO-8601, exclusieve bovengrens. Maximaal 90 dagen bereik.
queueIdneejaHerhaal de parameter om meerdere wachtrijen te filteren.
locationIdneejaHerhaal de parameter om meerdere locaties te filteren.
statusneejaEen van WAITING, CALLED, COMPLETED, CANCELED, SKIPPED, NO_SHOW.
cursorneeneeOndoorzichtige waarde uit nextCursor van de vorige pagina.
limitneeneeStandaard 100, maximaal 500.
Terminal window
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…"
}

Rijen bevatten nooit de bearer-hash van het ticket of persoonsgegevens die de klant heeft ingevoerd, zoals een naam, notities of groepsgrootte. Ze bevatten alleen ID’s, de status en tijdstempels van de levenscyclus.

Paginering: als nextCursor niet null is, geef je deze bij het volgende verzoek door als cursor. Gebruik dezelfde waarden voor from, to en de filters. Een nextCursor van null betekent dat je het einde van het bereik hebt bereikt.

Dezelfde filters als /v1/tickets (from/to verplicht, queueId/locationId/status herhaalbaar) minus cursor/limit — het volledige overeenkomende bereik wordt gestreamd als één CSV-respons, dus er is geen limiet van 500 rijen per pagina om omheen te werken bij een bulkuittreksel.

De kolomvolgorde is stabiel, maar parse kolommen op headernaam in plaats van vaste positie. De headerrij is altijd aanwezig en komt exact overeen met deze lijst:

id,number,queueId,locationId,status,createdAt,calledAt,completedAt,cancelledAt,skippedAt,noShowAt,calledByDeviceSessionId
Terminal window
curl "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.csv

De respons gebruikt Transfer-Encoding: chunked. Daardoor hoeft een export van 90 dagen met 100.000 rijen aan geen van beide kanten volledig in het geheugen te staan. Stuur de uitvoer rechtstreeks naar een bestand of parser.

Elk eindpunt dat from/to gebruikt, weigert een bereik van meer dan 90 dagen met 400. Haal gegevens incrementeel op (bijv. één aanroep per week) als je een langere geschiedenis nodig hebt — de tijdstempels van de ticketlevenscyclus (calledAt, completedAt, …) laten je wacht-/servicetijden reconstrueren zonder dezelfde rijen twee keer op te halen.

Elk token staat 60 verzoeken per minuut toe. De limiet geldt voor het token, niet voor het IP-adres. Elke respons bevat:

X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1751328000000

Een 429 draagt daarnaast Retry-After (seconden). Wacht en probeer het opnieuw na dat venster; een geplande synchronisatie elke paar minuten blijft ruim onder de limiet.

Voor een demo-organisatie geldt naast de limiet per minuut een extra limiet van 50 verzoeken per dag. Daarmee kun je een volledige integratie testen door wachtrijen en tickets op te halen en een CSV-export te maken. De dagelijkse limiet is niet geschikt voor productiegebruik. Bij overschrijding geeft de API een 429 terug met de oorzaak in de body:

{
"error": "demo_quota_exceeded",
"limit": 50,
"resetAt": "2026-01-02T09:00:00.000Z"
}

Demo-CSV-exports worden ook gemarkeerd, zodat een geëxporteerd bestand niet kan worden verward met productiedata: de bestandsnaam krijgt het voorvoegsel demo-, de respons draagt X-Jonot-Demo: 1, en er wordt een extra kolom demo toegevoegd aan de CSV. Betaalde exports blijven ongewijzigd — geen extra kolom, geen extra header. Een betaald abonnement heft het dagelijkse quotum op en verwijdert deze markeringen.

import requests
import 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())

Of lees de CSV-export rechtstreeks — pandas handelt de streaming-respons transparant af:

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}"},
)
  1. In Power BI Desktop: Get Data → Web.
  2. Kies Advanced en bouw de URL met je datumbereik, bijv. https://api.jonot.io/v1/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z.
  3. Voeg onder HTTP request header parameters een header toe met de naam Authorization en de waarde Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
  4. Klik op OK — Power BI detecteert de CSV en opent de tabelvoorbeeldweergave.
  5. Klik op Load (of eerst op Transform Data als je kolomtypen wilt instellen — createdAt/calledAt/enz. worden geïmporteerd als tekst; converteer ze in Power Query naar Date/Time).
  6. Stel een geplande vernieuwing in bij de Power BI-service als je op een vast ritme ophaalt; houd het bereik per vernieuwing ruim onder de 90 dagen.