--- title: "Pozycje: spadki (`getLosses`)" source: https://docs.senuto.com/modules/visibility_analysis/va-positions-getLosses api: POST /api/visibility_analysis/reports/positions/getLosses --- # Pozycje: spadki (`getLosses`) **`POST /api/visibility_analysis/reports/positions/getLosses`** Zwraca frazy kluczowe, dla których domena **straciła pozycje** w wybranym okresie (working mode = `decrease`). Każdy wiersz zawiera te same statystyki co `getData` (pozycja, widoczność, URL, CPC, liczba wyszukiwań, trendy, trudność, snippety SERP), ale zbiór jest ograniczony do fraz, których pozycja się pogorszyła — wartość `diff` w `position` odzwierciedla zmianę na gorsze. > **Ostrzeżenie:** > **Okres jest zaszyty na sztywno — ok. tygodnia.** Ta akcja nie przyjmuje żadnych parametrów dat. Porównywany jest najświeższy dostępny snapshot pozycji z najstarszym snapshotem z ostatniego tygodnia. Jeśli potrzebujesz własnego zakresu, użyj [`history/keywords/getLosses`](/modules/visibility_analysis/va-history-keywords-getLosses) z `date_min`/`date_max`. > > **Frazy utracone nie są tutaj widoczne.** Fraza, która wypadła poza TOP50, nie pojawi się w tej akcji, mimo że formalnie „spadła" — zwracany jest wyłącznie ruch **wewnątrz** TOP50. W rodzinie `positions/*` **nie ma odpowiednika `getLost`**, więc utraconych fraz nie da się stąd pobrać w ogóle; sięgnij po [`history/keywords/getLost`](/modules/visibility_analysis/va-history-keywords-getLost) i podaj daty ręcznie. > > Siostrzana [`getWins`](/modules/visibility_analysis/va-positions-getWins) zachowuje się **odwrotnie** — zawiera frazy nowo pozyskane (jako skok z pozycji `51`). Porównywanie `count` obu akcji zestawia więc dwie różnie zdefiniowane wielkości. Zachowanie może się w przyszłości ujednolicić — na dziś traktuj powyższe jako obowiązujący kontrakt. | Fraza | ID frazy | KID | Domena | Liczba słów | Pozycja | Pozycja poprz. | Zmiana pozycji | Wzrosty | Spadki | Bez zmian | Widoczność | Widoczność poprz. | Δ widoczności | Widoczność % | URL bieżący | URL poprzedni | URL zmiana | CPC | Wyszukiwania/mies. | Trend (12 mies.) | Szczyt trendu | Trudność | Snippety SERP | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | dresy damskie 4f | 2864 | 0009edce5b257ad4363766e56bef5c74 | zalando.pl | 3 | 17 | 15 | 2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | zalando.pl/odziez-damska-spodnie-treningowe/4f/ | zalando.pl/odziez-damska-spodnie-treningowe/4f/ | 0 | 0.47 | 1600 | [2400,2400,1900,2400,1300,1000,880,1300,1600,1600,1600,1600] | | 30 | ["image_thumbs","people_also_ask"] | _zalando.pl — fraza, która straciła pozycję. Dodatni „diff” oznacza spadek. Wszystkie pola wiersza (poza mapą historii `statistics.position.history`, która ma zmienne klucze-daty — jest w JSON i sekcji „Struktura odpowiedzi”)._ --- ## Żądanie `POST` `/api/visibility_analysis/reports/positions/getLosses` Nagłówki: `Authorization: Bearer `, `Content-Type: application/json`. ### Struktura żądania **Podstawowy** ```jsonc filename="żądanie-podstawowe.jsonc" { "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "limit": 2 } ``` **Rozszerzony** ```jsonc filename="żądanie-rozszerzone.jsonc" { "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "limit": 10, "page": 1, "order": { "prop": "statistics.position.current", "dir": "desc" }, "filtering": [] } ``` **cURL** ```bash curl --location --request POST 'https://api.senuto.com/api/visibility_analysis/reports/positions/getLosses' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer $YOUR_TOKEN_HERE' \ --data-raw '{ "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "limit": 2 }' ``` ### Parametry ```ts type PositionsGetLossesRequest = { /** * **Wymagane**. Domena, subdomena, katalog lub URL do analizy — interpretowane zgodnie z `fetch_mode`. */ domain: string; /** * **Wymagane**. Sposób interpretacji `domain`. * - `topLevelDomain` — cała domena (najczęstszy przypadek; "domena") * - `subdomain` — pojedyncza subdomena * - `catalog` — ścieżka/katalog * - `url` — dokładny URL */ fetch_mode: 'topLevelDomain' | 'subdomain' | 'catalog' | 'url'; /** * Liczba wierszy na stronę. Nieujemna liczba całkowita. * @default 10 */ limit?: number; /** * Numer strony. Nieujemna liczba całkowita. * @default 1 */ page?: number; /** * Sortowanie wyników — **pojedynczy obiekt**, nie tablica. * Dozwolone `prop`: `statistics.position.current|previous|diff`, * `statistics.visibility.current|previous|diff`, `statistics.searches.current`, * `statistics.cpc.current`, `statistics.difficulty.current`, * `statistics.url.is_change`, `words_count`. * Zły kształt lub nieznany klucz NIE zwraca błędu — API po cichu wraca * do sortu domyślnego (`keyword_id` rosnąco). */ order?: { prop: string; dir: 'asc' | 'desc' }; /** * Dyrektywy filtrowania. Pusta tablica = brak filtrowania. */ filtering?: unknown[]; } export default PositionsGetLossesRequest ``` > **Ostrzeżenie:** > Nazwy parametrów różnią się od starej dokumentacji: jest to **`filtering`** (nie `filters`) oraz **`order`** (nie `sort_by` / `sort_order`). Uwaga na kształt `order`: to **obiekt `{ "prop": …, "dir": … }`** — forma tablicowa `[{ field, direction }]` jest przez API **ignorowana po cichu** (zwraca 200 z sortem domyślnym po `keyword_id`). > **Ostrzeżenie:** > Zarówno **`domain`**, jak i **`fetch_mode`** są **wymagane**; pominięcie `fetch_mode` zwraca `418` z `invalid_data`. ## Odpowiedź Po pomyślnym żądaniu otrzymujesz `data` (tablicę fraz, które straciły pozycje) oraz `pagination`. W polu `position`: `previous` to pozycja wcześniejsza, `current` — bieżąca, a dodatni `diff` oznacza spadek (wyższa liczba = gorsza pozycja). **Skrócona** ```json filename="przykładowa-odpowiedź (skrócona)" { "success": true, "data": [ { "keyword_id": 2864, "keyword": "dresy damskie 4f", "statistics": { "position": { "current": 17, "previous": 15, "diff": 2 } /* … */ } } ], "pagination": { "page_count": 2057, "current_page": 1, "has_next_page": true, "has_prev_page": false, "count": 4114, "limit": 2 } } ``` **Pełna** ```json filename="przykładowa-odpowiedź (200)" { "success": true, "data": [ { "keyword_id": 2864, "kid": "0009edce5b257ad4363766e56bef5c74", "domain": "zalando.pl", "keyword": "dresy damskie 4f", "words_count": 3, "statistics": { "position": { "current": 17, "previous": 15, "diff": 2, "changes": { "wins": 0, "losses": 1, "no_changes": 0 }, "history": { "2026-05-24": { "position": 15, "has_serp": true }, "2026-06-25": { "position": 17, "has_serp": true } } }, "visibility": { "current": 0, "previous": 0, "diff": 0, "percent": 0, "history": null }, "url": { "current": "zalando.pl/odziez-damska-spodnie-treningowe/4f/", "previous": "zalando.pl/odziez-damska-spodnie-treningowe/4f/", "is_change": 0 }, "cpc": { "current": 0.47 }, "searches": { "current": 1600 }, "trends": { "history": [2400, 2400, 1900, 2400, 1300, 1000, 880, 1300, 1600, 1600, 1600, 1600], "peak": null }, "difficulty": { "current": 30 }, "snippets": { "current": ["image_thumbs", "people_also_ask"] } } } ], "pagination": { "page_count": 2057, "current_page": 1, "has_next_page": true, "has_prev_page": false, "count": 4114, "limit": 2 } } ``` ### Struktura odpowiedzi ```ts type PositionsResponse = { /** `true` przy powodzeniu; przy błędzie `false` i koperta z `error` */ success: boolean; /** Zwrócone wiersze fraz (spadki) */ data: PositionRow[]; /** Metadane paginacji */ pagination: { page_count: number; current_page: number; has_next_page: boolean; has_prev_page: boolean; count: number; limit: number; }; } type PositionRow = { keyword_id: number; kid: string; domain: string; keyword: string; words_count: number; statistics: { position: { current: number; previous: number; diff: number; changes: { wins: number; losses: number; no_changes: number }; history: Record | [] }; visibility: { current: number; previous: number; diff: number; percent: number; history: null }; url: { current: string; previous: string; is_change: 0 | 1 }; cpc: { current: number }; searches: { current: number }; trends: { history: number[]; peak: number | null }; difficulty: { current: number }; snippets: { current: string[] }; }; } export default PositionsResponse ``` ## Błędy ```ts type ErrorResponse = { success: false; data: { error: { /** np. invalid_data, invalid_filtering, unreachable_data, timeout, database, unknown */ type: string; message: string; /** pole -> reguła -> komunikat (dla invalid_data) */ params?: Record>; }; }; } export default ErrorResponse ``` > **Błąd:** > **`418`** jest zwracane również w przypadku błędów walidacji — nie tylko przy ograniczaniu liczby żądań. Brak `fetch_mode` → > `{"success":false,"data":{"error":{"type":"invalid_data","params":{"fetch_mode":{"_required":"This field is required"}}}}}`. ## Powiązane akcje - `getData` — bieżące pozycje (taki sam kształt żądania) - `getWins` — frazy, które **zyskały** pozycje (working mode = `increase`) - `getLosses` — frazy, które **straciły** pozycje (ta strona) - `getKeywordHistory` — pełna historia pozycji dla pojedynczej frazy (`keyword_id` + `kid` + `domain` + `fetch_mode`)