Przejdź do głównej zawartości

Analityczne API tylko do odczytu

HTTP API api.jonot.io/v1/* daje dostęp tylko do odczytu do danych biletów i kolejek Twojej organizacji. Zamiast logowania administratora uwierzytelniasz się tokenem bearer. Używaj tego API, aby pobierać dane do hurtowni danych, narzędzia BI lub własnego panelu.

  1. Otwórz admin.jonot.io/settings/integrations.
  2. Kliknij zakładkę API tokens.
  3. Kliknij Create token, nadaj mu nazwę (np. „Power BI”) i potwierdź.
  4. Skopiuj token natychmiast — jest pokazywany tylko raz i nie można go odzyskać. Jeśli go zgubisz, odwołaj go i utwórz nowy.

Tokeny mają prefiks jot_ i nigdy nie wygasają same z siebie; odwołuj je w tej samej zakładce, gdy nie są już potrzebne.

Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
StatusZnaczenie
401Token brakujący, nieprawidłowy, nieznany lub odwołany.
402Token prawidłowy, ale organizacja nie ma włączonej funkcji API.
429Przekroczono limit zapytań — zobacz Limity zapytań poniżej.
400Nieprawidłowe parametry zapytania lub zakres dat dłuższy niż 90 dni.

Zwraca lokalizacje i kolejki Twojej organizacji, bez filtrowania i bez paginacji:

Okno terminala
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"
}
]
}
]
}

Użyj zwróconych wartości id, aby filtrować /v1/tickets oraz eksport CSV według queueId / locationId.

Paginowany odczyt biletów w obrębie Twojej organizacji.

ParametrWymaganyPowtarzalnyUwagi
fromtaknieISO-8601, dolna granica dla createdAt, włącznie.
totaknieISO-8601, górna granica, wyłącznie. Maksymalnie 90 dni zakresu.
queueIdnietakPowtórz parametr, aby filtrować wiele kolejek.
locationIdnietakPowtórz parametr, aby filtrować wiele lokalizacji.
statusnietakJedna z wartości WAITING, CALLED, COMPLETED, CANCELED, SKIPPED, NO_SHOW.
cursornienieNieprzezroczysta wartość z pola nextCursor poprzedniej strony.
limitnienieDomyślnie 100, maksymalnie 500.
Okno terminala
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…"
}

Wiersze nigdy nie zawierają hasza uwierzytelniającego biletu ani danych osobowych wprowadzonych przez klienta, takich jak imię i nazwisko, notatki czy liczba osób. Zawierają wyłącznie identyfikatory, status i znaczniki czasu cyklu życia.

Paginacja: gdy nextCursor nie jest równe null, przekaż jego wartość jako cursor w kolejnym zapytaniu. Zachowaj te same wartości from, to i filtrów. Wartość null w nextCursor oznacza koniec zakresu.

Ten punkt końcowy przyjmuje te same filtry co /v1/tickets: from i to są wymagane, a queueId, locationId i status można powtarzać. Nie przyjmuje cursor ani limit. Cały pasujący zakres jest przesyłany strumieniowo jako jedna odpowiedź CSV, więc limit 500 wierszy na stronę tu nie obowiązuje.

Kolejność kolumn jest stała, ale odczytuj kolumny według nazwy nagłówka, a nie stałej pozycji. Wiersz nagłówka jest zawsze obecny i dokładnie odpowiada tej liście:

id,number,queueId,locationId,status,createdAt,calledAt,completedAt,cancelledAt,skippedAt,noShowAt,calledByDeviceSessionId
Okno terminala
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

Odpowiedź używa Transfer-Encoding: chunked. Eksport obejmujący 90 dni i 100 000 wierszy nie musi pozostawać w pamięci po żadnej ze stron. Skieruj go bezpośrednio do pliku lub parsera.

Każdy punkt końcowy przyjmujący from i to odrzuca z kodem 400 zakres dłuższy niż 90 dni. Jeśli potrzebujesz dłuższej historii, pobieraj krótsze zakresy, na przykład po jednym zapytaniu na tydzień. Znaczniki czasu cyklu życia, takie jak calledAt i completedAt, pozwalają obliczyć czasy oczekiwania i obsługi bez dwukrotnego pobierania tych samych wierszy.

Każdy token pozwala na 60 zapytań na minutę. Limit dotyczy tokena, a nie adresu IP. Każda odpowiedź zawiera:

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

Odpowiedź 429 zawiera dodatkowo nagłówek Retry-After (w sekundach). Odczekaj ten czas przed ponowną próbą. Synchronizacja zaplanowana co kilka minut mieści się w limicie z zapasem.

Organizację demonstracyjną obowiązuje dodatkowy limit 50 zapytań dziennie. Limit na minutę obowiązuje tak samo. Na demonstracyjnym API przetestujesz całą integrację: wyświetlisz listę kolejek, pobierzesz bilety i utworzysz eksport CSV. Limit dzienny nie wystarcza do użytku produkcyjnego. Po jego przekroczeniu API zwraca 429 z treścią wskazującą przyczynę:

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

Eksporty CSV z konta demonstracyjnego są dodatkowo oznaczone, aby nie można było pomylić ich z danymi produkcyjnymi: nazwa pliku ma przedrostek demo-, odpowiedź zawiera nagłówek X-Jonot-Demo: 1, a na końcu CSV dochodzi kolumna demo. Płatne eksporty pozostają bez zmian — bez dodatkowej kolumny i bez dodatkowego nagłówka. Wykupienie płatnego planu znosi limit dzienny i usuwa oznaczenia.

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

Możesz też odczytać eksport CSV bezpośrednio — pandas obsługuje odpowiedź strumieniową bez dodatkowej konfiguracji:

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. W Power BI Desktop: Get Data → Web.
  2. Wybierz Advanced i zbuduj adres URL z żądanym zakresem dat, np. https://api.jonot.io/v1/exports/tickets.csv?from=2026-06-01T00:00:00Z&to=2026-07-01T00:00:00Z.
  3. W sekcji HTTP request header parameters dodaj nagłówek o nazwie Authorization z wartością Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
  4. Kliknij OK — Power BI wykryje plik CSV i otworzy podgląd tabeli.
  5. Kliknij Load (lub najpierw Transform Data, jeśli chcesz ustawić typy kolumn — createdAt/calledAt itd. są importowane jako tekst; przekształć je w Power Query na typ Date/Time).
  6. Ustaw w usłudze Power BI zaplanowane odświeżanie, jeśli pobierasz dane cyklicznie; utrzymuj zakres z zapasem poniżej 90 dni na odświeżenie.