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.
Uzyskiwanie tokena
Dział zatytułowany „Uzyskiwanie tokena”- Otwórz admin.jonot.io/settings/integrations.
- Kliknij zakładkę API tokens.
- Kliknij Create token, nadaj mu nazwę (np. „Power BI”) i potwierdź.
- 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.
Uwierzytelnianie
Dział zatytułowany „Uwierzytelnianie”Authorization: Bearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| Status | Znaczenie |
|---|---|
401 | Token brakujący, nieprawidłowy, nieznany lub odwołany. |
402 | Token prawidłowy, ale organizacja nie ma włączonej funkcji API. |
429 | Przekroczono limit zapytań — zobacz Limity zapytań poniżej. |
400 | Nieprawidłowe parametry zapytania lub zakres dat dłuższy niż 90 dni. |
Punkty końcowe
Dział zatytułowany „Punkty końcowe”GET /v1/queues
Dział zatytułowany „GET /v1/queues”Zwraca lokalizacje i kolejki Twojej organizacji, bez filtrowania i bez paginacji:
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.
GET /v1/tickets
Dział zatytułowany „GET /v1/tickets”Paginowany odczyt biletów w obrębie Twojej organizacji.
| Parametr | Wymagany | Powtarzalny | Uwagi |
|---|---|---|---|
from | tak | nie | ISO-8601, dolna granica dla createdAt, włącznie. |
to | tak | nie | ISO-8601, górna granica, wyłącznie. Maksymalnie 90 dni zakresu. |
queueId | nie | tak | Powtórz parametr, aby filtrować wiele kolejek. |
locationId | nie | tak | Powtórz parametr, aby filtrować wiele lokalizacji. |
status | nie | tak | Jedna z wartości WAITING, CALLED, COMPLETED, CANCELED, SKIPPED, NO_SHOW. |
cursor | nie | nie | Nieprzezroczysta wartość z pola nextCursor poprzedniej strony. |
limit | nie | nie | Domyślnie 100, maksymalnie 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…"}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.
GET /v1/exports/tickets.csv
Dział zatytułowany „GET /v1/exports/tickets.csv”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,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.csvOdpowiedź 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.
Limit zakresu 90 dni
Dział zatytułowany „Limit zakresu 90 dni”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.
Limity zapytań
Dział zatytułowany „Limity zapytań”Każdy token pozwala na 60 zapytań na minutę. Limit dotyczy tokena, a nie adresu IP. Każda odpowiedź zawiera:
X-RateLimit-Remaining: 42X-RateLimit-Reset: 1751328000000Odpowiedź 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.
Organizacje demonstracyjne
Dział zatytułowany „Organizacje demonstracyjne”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.
Python + pandas
Dział zatytułowany „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())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}"},)Power BI (łącznik Web)
Dział zatytułowany „Power BI (łącznik Web)”- W Power BI Desktop: Get Data → Web.
- 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. - W sekcji HTTP request header parameters dodaj nagłówek o nazwie
Authorizationz wartościąBearer jot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. - Kliknij OK — Power BI wykryje plik CSV i otworzy podgląd tabeli.
- Kliknij Load (lub najpierw Transform Data, jeśli chcesz ustawić typy kolumn —
createdAt/calledAtitd. są importowane jako tekst; przekształć je w Power Query na typDate/Time). - 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.