Skrivebeskyttet analytics-API
HTTP-API’et api.jonot.io/v1/* giver skrivebeskyttet adgang til
organisationens kølap- og kødata. Brug et bearer-token i stedet for et
Admin-login. API’et kan hente data til et datalager, BI-værktøj eller
tilpasset dashboard.
Sådan får du et token
Sektion kaldt “Sådan får du et token”- Åbn admin.jonot.io/settings/integrations.
- Klik på fanen API tokens.
- Klik på Create token, giv det et navn (f.eks. “Power BI”), og bekræft.
- Kopiér tokenet med det samme — det vises kun én gang og kan ikke gendannes. Mister du det, skal du tilbagekalde det og oprette et nyt.
Tokens begynder med jot_ og udløber ikke automatisk. Tilbagekald et token
fra samme fane, når du ikke længere bruger det.
Godkendelse
Sektion kaldt “Godkendelse”Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| Status | Betydning |
|---|---|
401 | Token mangler, er ugyldigt, ukendt eller er blevet tilbagekaldt. |
402 | Gyldigt token, men organisationen har ikke aktiveret API-funktionen. |
429 | Ratelimit overskredet — se Ratelimits nedenfor. |
400 | Ugyldige forespørgselsparametre, eller et tidsrum på over 90 dage. |
Endpoints
Sektion kaldt “Endpoints”GET /v1/queues
Sektion kaldt “GET /v1/queues”Returnerer din organisations lokationer og køer, ufiltreret og upagineret:
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" } ] } ]}Brug de returnerede id-værdier til at filtrere /v1/tickets og
CSV-eksporten efter queueId / locationId.
GET /v1/tickets
Sektion kaldt “GET /v1/tickets”Pagineret kølap-læsning, afgrænset til din organisation.
| Parameter | Påkrævet | Gentagelig | Bemærkninger |
|---|---|---|---|
from | ja | nej | ISO-8601, inklusiv nedre grænse for createdAt. |
to | ja | nej | ISO-8601, eksklusiv øvre grænse. Maks. 90 dages tidsrum. |
queueId | nej | ja | Gentag parameteren for at filtrere flere køer. |
locationId | nej | ja | Gentag parameteren for at filtrere flere lokationer. |
status | nej | ja | En af WAITING, CALLED, COMPLETED, CANCELED, SKIPPED, NO_SHOW. |
cursor | nej | nej | Uigennemsigtig værdi fra forrige sides nextCursor. |
limit | nej | nej | Standard 100, maks. 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…"}Rækkerne indeholder ikke kølappens bearer-hash eller personoplysninger, som kunden har indtastet, for eksempel navn, noter eller gruppestørrelse. De indeholder kun id’er, status og tidsstempler fra livscyklussen.
Paginering: når nextCursor ikke er null, skal du sende den som cursor
i næste forespørgsel for at fortsætte, hvor du slap (samme from/to/filtre).
Et nextCursor på null betyder, at du har nået slutningen af tidsrummet.
GET /v1/exports/tickets.csv
Sektion kaldt “GET /v1/exports/tickets.csv”Brug de samme filtre som til /v1/tickets: from og to er påkrævet, og queueId, locationId og status kan gentages. cursor og limit bruges ikke. Hele det valgte tidsrum sendes som ét CSV-svar uden grænsen på 500 rækker pr. side.
Kolonnerækkefølgen er stabil, men fortolk kolonner ud fra overskriftsnavnet og ikke en fast position. Overskriftsrækken er altid til stede og matcher nøjagtigt denne liste:
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.csvSvaret streames (Transfer-Encoding: chunked), så en 90-dages eksport med
100.000 rækker ikke skal gemmes samlet i hukommelsen. Send den direkte til en
fil eller parser.
90-dages grænse for tidsrum
Sektion kaldt “90-dages grænse for tidsrum”Alle endpoints, der tager from/to, afviser et tidsrum på over 90 dage med
400. Hent data trinvist (f.eks. ét kald pr. uge), hvis du har brug for en
længere historik — kølappens livscyklus-tidsstempler (calledAt,
completedAt, …) lader dig rekonstruere vente-/betjeningstider uden at
hente de samme rækker to gange.
Ratelimits
Sektion kaldt “Ratelimits”Hvert token kan sende 60 forespørgsler pr. minut. Grænsen følger tokenet og ikke IP-adressen. Hvert svar indeholder:
X-RateLimit-Remaining: 42X-RateLimit-Reset: 1751328000000Et 429-svar indeholder desuden Retry-After (sekunder). Vent den
tidsperiode, før du prøver igen; en planlagt synkronisering hvert par
minutter holder sig komfortabelt under grænsen.
Demoorganisationer
Sektion kaldt “Demoorganisationer”En demoorganisation bruger samme API med en ekstra grænse på 50 anmodninger om dagen. Det er nok til at afprøve en integration ved at liste køer, hente kølapper og lave en CSV-eksport, men ikke til produktion. Hvis grænsen overskrides, returnerer API’et 429 med årsagen:
{ "error": "demo_quota_exceeded", "limit": 50, "resetAt": "2026-01-02T09:00:00.000Z"}CSV-eksporter fra demoer er også markeret, så en eksporteret fil ikke kan forveksles med produktionsdata: filnavnet har præfikset demo-, svaret indeholder X-Jonot-Demo: 1, og en ekstra demo-kolonne tilføjes til sidst i CSV-filen. Betalte eksporter er uændrede — ingen ekstra kolonne, ingen ekstra header. Et betalt abonnement ophæver den daglige kvote og fjerner markeringerne.
Python + pandas
Sektion kaldt “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())Du kan også læse CSV-eksporten direkte. pandas håndterer det streamede svar:
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 (webforbindelse)
Sektion kaldt “Power BI (webforbindelse)”- I Power BI Desktop: Get Data → Web.
- Vælg Advanced, og byg URL’en med dit datointerval, f.eks.
https://api.jonot.io/v1/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z. - Under HTTP request header parameters skal du tilføje en header ved navn
Authorizationmed værdienBearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. - Klik på OK — Power BI registrerer CSV-filen og åbner tabelforhåndsvisningen.
- Klik på Load (eller først Transform Data, hvis du vil angive kolonnetyper —
createdAt/calledAt/osv. importeres som tekst; konvertér dem tilDate/Timei Power Query). - Angiv en planlagt opdatering i Power BI-tjenesten, hvis du henter data løbende; hold intervallet komfortabelt under 90 dage pr. opdatering.