Błędy
Gdy żądanie się nie powiedzie, API zwraca kopertę z success: false i obiektem error. Struktura jest spójna w całym API.
Koperta błędu
| Name | Type | Default |
|---|---|---|
success | falseZawsze | |
data | { error: { type: string; message: string; params?: Record<string, Record<string, string>>; }; } |
Status HTTP 418 — najważniejsze
Status 418 to w tym API generyczny błąd walidacji żądania, a nie wyłącznie przekroczenie limitu zapytań. Zdecydowana większość 418 to type: "invalid_data" — brakujące lub nieprawidłowe pole. Sprawdzaj data.error.type i data.error.params, zanim uznasz błąd za rate limit.
Typowe 418 (invalid_data) — brak wymaganego pola:
{
"success": false,
"data": {
"error": {
"type": "invalid_data",
"message": "Given data is invalid, please check the documentation or contact Administrator",
"params": { "fetch_mode": { "_required": "This field is required" } }
}
}
}Status HTTP 404 — trzy różne przyczyny
404 w tym API nie oznacza po prostu „zły adres”. Rozróżnisz przypadki po tym, co przyszło w treści:
| Treść odpowiedzi | Znaczenie | Co zrobić |
|---|---|---|
{"success": false, "message": ""} | Trasa nie istnieje albo żądanie jest nieuwierzytelnione (wtedy poprzedza je 302 na …/users/login) | Sprawdź pisownię ścieżki (niżej), a potem token |
| Strona HTML z nagłówkiem „Error / Not Found” | Trasa istnieje, ale wskazany zasób nie — albo akcja w ogóle nie dostała identyfikatora | Sprawdź, czy parametr idzie tam, gdzie trzeba (query string vs ciało) i czy zasób należy do Twojego konta |
Nieważny lub brakujący token daje 302, a po przekierowaniu 404 — nie 401. Żądanie bez
nagłówka Authorization oraz z tokenem po terminie ważności dostaje 302 z nagłówkiem Location
na /api/<moduł>/users/login, a pod tym adresem czeka 404 {"success": false, "message": ""} —
dokładnie to samo, co po literówce w ścieżce. Klient podążający za przekierowaniami (curl -L,
requests, axios) pokaże 404; Postman z wyłączonym podążaniem zatrzyma się na 302.
Zanim zaczniesz debugować ścieżkę, pobierz świeży token (patrz Autoryzacja).
Komunikat jest pusty celowo, produkcyjne API nie ujawnia szczegółów wyjątku.
Konwencja adresów — najczęstsza przyczyna 404
Ścieżka ma postać /api/<moduł>/<sekcja>/<kontroler>/<akcja>, przy czym człony i akcja rządzą się różnymi regułami:
- Moduł, sekcja i kontroler:
snake_case—visibility_analysis,ai_overviews,serp_analysis. - Akcja:
camelCase—getDomainStatistics,getKeywordHistory. Zamiana akcji nasnake_casealbokebab-casedaje404, mimo że endpoint istnieje. - Myślnik zamiast podkreślenia w module (
visibility-analysis) też kończy się404. - Pominięty człon sekcji (
/api/visibility_analysis/dashboard/…zamiast…/reports/dashboard/…) —404.
/api/visibility_analysis/reports/dashboard/getDomainStatistics → 200
/api/visibility_analysis/reports/dashboard/get_domain_statistics → 404 akcja w snake_case
/api/visibility-analysis/reports/dashboard/getDomainStatistics → 404 myślnik w module
/api/visibility_analysis/dashboard/getDomainStatistics → 404 brak członu "reports"Sama wielkość liter w nazwie akcji akurat nie ma znaczenia (getdomainstatistics też odpowie 200) —
decyduje brak separatorów. Nie opieraj się jednak na tym: trzymaj się pisowni podanej na stronie endpointu.
Kategorie błędów (type)
type | Znaczenie | Częsta przyczyna |
|---|---|---|
invalid_data | Żądanie nie przeszło walidacji | Brak wymaganego pola, zła wartość (np. nieznany fetch_mode, country_id, aggregation_type) |
invalid_filtering | Nieprawidłowy parametr filtering | Klucz filtra nieobsługiwany przez ten endpoint |
unauthorized / Unauthorized access | Brak dostępu do zasobu | Cudzy lub nieistniejący project_id / group_id / keyword_id |
unreachable_data | Dane chwilowo niedostępne | Problem po stronie źródła danych |
timeout | Przekroczono czas przetwarzania | Bardzo szeroki zakres / duża domena |
database | Błąd warstwy danych | Bywa zwracany także jako HTTP 500 z surową stroną HTML (patrz niżej) |
Częste pułapki
Cudzy/nieistniejący zasób → 418 Unauthorized access, nie 404. Podanie project_id lub group_id spoza konta zwraca błąd walidacji dostępu, a nie „nie znaleziono”. Konto administratora (role_id = 1) omija część kontroli dostępu.
Zła metoda HTTP. Część akcji akceptuje wyłącznie GET (parametry w query stringu) — wysłanie ich metodą POST w ciele JSON zwraca 405 (Method Not Allowed) albo 418, bo walidator widzi puste pola. Metoda jest podana na stronie każdego endpointu.
Konto bez dostępu do API → 403, nie 418. Ważny token na koncie bez aktywnego planu albo bez
dodatku Dostęp do API daje 403 {"success": false, "message": ""}. Treść jest pusta, więc ten przypadek
rozpoznajesz po samym statusie (patrz Dostęp do API).
HTTP 500 z surową stroną HTML. Niektóre endpointy zwracają obecnie nieobsłużony wyjątek (500, treść to strona HTML, nie JSON) niezależnie od poprawności żądania — to znane usterki backendu, nie błąd Twojej integracji. Buduj klienta odpornie: gdy odpowiedź nie jest JSON-em, potraktuj ją jako błąd serwera.
Odwrócony komunikat zakresu dat. W części raportów przy date_min > date_max komunikat błędu bywa odwrócony (mówi o date_max, choć problem dotyczy date_min). Waliduj kolejność dat po swojej stronie.
Odpowiedź 200, ale dane są puste lub zerowe
To nie jest błąd — żądanie przeszło walidację, tylko dla podanych kryteriów nie ma danych. Kolejność sprawdzania, od najczęstszej przyczyny:
- Zły
fetch_mode. Host z subdomeną (blog.example.com) w trybietopLevelDomainliczy wyłącznie frazy, na których rankuje ten konkretny host — a tych zwykle nie ma. Zwalidowane:blog.senuto.comwtopLevelDomainzwraca0, a wsubdomain— 316 fraz w TOP10. Patrzfetch_mode. - Domena spoza indeksu. Senuto liczy widoczność na własnym zbiorze fraz per rynek. Domena, która nie
rankuje w TOP50 na żadną frazę z bazy, zwróci zera — tak samo jak domena nieistniejąca (sprawdzone:
dla wymyślonej domeny raport dashboardu odpowiada
200z samymi zerami, nie błędem). - Zły rynek (
country_id). Bez tego pola raporty liczą na bazie domyślnej (Polska 1.0). Domena czeska sprawdzana na polskiej bazie da zera. Część danych istnieje wyłącznie w bazie PL 2.0 (country_id: 200) — np. raport intencji AI Overviews nacountry_id: 1zwraca pustą tablicę dla każdej domeny. - Zakres dat sprzed pojawienia się domeny w bazie — raporty historyczne zwrócą pustą serię dla okresu, w którym nie było jeszcze pomiarów.
filteringodcina wszystko. Filtr niepasujący do żadnego wiersza daje pustą tablicę, a nie błąd — sprawdź go, usuwając filtry po kolei.
Rozróżnienie, które warto zaszyć w kliencie: data: [] (albo same zera) = brak danych dla kryteriów,
success: false = odrzucone żądanie. Pierwsze nie jest powodem do retry — powtórzone da to samo.
418 w trakcie długiego pobierania albo w pętli
Typowy zgłaszany scenariusz: integracja (n8n, Make, własny skrypt) pobiera dane od kilku minut i nagle
zaczyna dostawać 418, choć te same żądania wcześniej działały. Prawdziwe przyczyny, w kolejności:
- Wyczerpany limit dobowy. Najczęstsza. Komunikat wygląda tak:
You have reached daily limit of queries. Daily limit value is N. Limity są per konto, nie per token, więc pętla w integracji rywalizuje o ten sam licznik co praca w aplikacji. Stan sprawdzisz przezGET /api/users/getLimits— ten odczyt nic nie zużywa. - Zmienna w pętli, która czasem jest pusta. Iterując po liście domen czy fraz łatwo trafić na wiersz
z pustą wartością — walidator zwróci
418zparamswskazującym pole. Zalogujdata.error.params, a znajdziesz sprawcę w jednym kroku. - Zasób spoza konta.
project_idalbogroup_idinnego użytkownika daje418 Unauthorized access(a nie404), co w pętli po projektach wygląda jak losowa awaria.
Nie myl tego z wygaśnięciem tokenu — token po terminie ważności daje 302 na …/users/login,
a po przekierowaniu 404 z pustym message, nie 418. Jeśli integracja działała miesiąc i nagle
„wszystkie endpointy zniknęły”, to token (patrz Status HTTP 404).
Klienci HTTP i platformy no-code często opakowują treść błędu we własny komunikat
(np. n8n pokazuje „Your request is invalid”). Zawsze zaglądaj do surowego ciała odpowiedzi —
data.error.type i data.error.params mówią, co naprawdę odrzucono.
500 / 503 — awaria czy mój błąd?
| Objaw | Najpewniej | Co zrobić |
|---|---|---|
500 na jednym endpoincie, inne działają | znana usterka tego endpointu (patrz wyżej) | zgłoś do supportu, obejdź innym raportem |
500/503 na wszystkich endpointach, także GET /api/users/whoami | awaria po stronie API | ponów z backoffem, potem zgłoś |
418/404/302 na wszystkich | to nie awaria — patrz sekcje wyżej (limit, token) | sprawdź token i limity |
Najprostszy test rozstrzygający: wywołaj GET /api/users/whoami. To najlżejszy endpoint w API — jeśli on
odpowiada 200, backend żyje i problem jest w konkretnym żądaniu.
Bieżące informacje o awariach i pracach serwisowych publikujemy na komunikat.senuto.com (strona tymczasowa) — zajrzyj tam, zanim zaczniesz debugować własny kod.
Przy masowych 5xx ponawiaj z wykładniczym backoffem (np. 1 s, 2 s, 4 s, 8 s… do kilku minut), a nie
w pętli co sekundę. Gdy po kilkunastu minutach nic się nie zmienia, zgłoś do supportu i podaj: pełny URL
żądania, metodę, czas z dokładnością do minuty (ze strefą), ciało żądania bez tokenu oraz surową odpowiedź
z nagłówkami. Z tym zestawem sprawa idzie od razu do zespołu API zamiast wracać z prośbą o szczegóły.
Obsługa po stronie klienta — wzorzec
// odpowiedź = wyślij żądanie
// jeśli odpowiedź nie jest JSON-em → błąd serwera (np. 500 HTML)
// w przeciwnym razie:
// jeśli odpowiedź.success == false:
// switch (odpowiedź.data.error.type):
// "invalid_data" → popraw pola z error.params (mapa pole → reguła)
// "invalid_filtering"→ sprawdź klucze filtra dla tego endpointu
// "unauthorized" → sprawdź dostęp do project_id / zasobu
// "timeout" → zawęź zakres i ponów
// inne → potraktuj jak błąd tymczasowy / zgłoś