--- title: "Pozycje: historia frazy (`getKeywordHistory`)" source: https://docs.senuto.com/modules/visibility_analysis/va-positions-getKeywordHistory api: POST /api/visibility_analysis/reports/positions/getKeywordHistory --- # Pozycje: historia frazy (`getKeywordHistory`) **`POST /api/visibility_analysis/reports/positions/getKeywordHistory`** Zwraca pełną historię pozycji **pojedynczej frazy kluczowej** dla wskazanej domeny. W odpowiedzi otrzymujesz mapę `history_positions`, w której kluczem jest data pomiaru, a wartością pozycja oraz informacja o obecności snippetów SERP w danym dniu. Identyfikatory frazy (`keyword_id` oraz `kid`) pozyskujesz z `positions/getData`. --- ## Żądanie `POST` `/api/visibility_analysis/reports/positions/getKeywordHistory` Nagłówki: `Authorization: Bearer `, `Content-Type: application/json`. ### Struktura żądania **Podstawowy** ```jsonc filename="żądanie-podstawowe.jsonc" { "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "keyword_id": null, "kid": null } ``` **Rozszerzony** ```jsonc filename="żądanie-rozszerzone.jsonc" { "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "keyword_id": null, "kid": null, "limit": 10, "page": 1 } ``` **cURL** ```bash curl --location --request POST 'https://api.senuto.com/api/visibility_analysis/reports/positions/getKeywordHistory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer $YOUR_TOKEN_HERE' \ --data-raw '{ "domain": "zalando.pl", "fetch_mode": "topLevelDomain", "keyword_id": null, "kid": null }' ``` ### Parametry ```ts type PositionsGetKeywordHistoryRequest = { /** * **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'; /** * **Wymagane**. Numeryczny identyfikator frazy. Pozyskaj go z `positions/getData` (pole `keyword_id`). * Realny `keyword_id` (i odpowiadający mu `kid`) pobierzesz z `POST /api/visibility_analysis/reports/positions/getData`. */ keyword_id: number; /** * **Wymagane**. Hash identyfikujący frazę w kontekście domeny. Pozyskaj go z `positions/getData` (pole `kid`). */ kid: string; /** * Liczba wierszy na stronę. Nieujemna liczba całkowita. * @default 10 */ limit?: number; /** * Numer strony. Nieujemna liczba całkowita. * @default 1 */ page?: number; /** * ⚠️ **Bez zastosowania w tym endpoincie.** Odpowiedź to mapa * `history_positions` (klucz = data pomiaru), nie lista — nie ma czego * sortować, a kontroler nie przekazuje `order` do komponentu. * Zweryfikowane na prod: dir asc i desc zwracają identyczną mapę. */ order?: unknown; /** * ⚠️ **Bez zastosowania w tym endpoincie.** Endpoint nie odczytuje `filtering` * (zweryfikowane). Zweryfikowane * na prod: nieznany klucz filtra NIE zwraca `418` (jest po cichu ignorowany), * a wynik jest identyczny jak bez `filtering`. Zawężanie historii rób po stronie klienta. */ filtering?: unknown[]; } export default PositionsGetKeywordHistoryRequest ``` > **Ostrzeżenie:** > Ten endpoint zwraca **mapę** historii pozycji (klucz = data), a nie stronicowaną listę — parametry `order`, `filtering`, `limit` i `page` nie mają tu zastosowania (`filtering` jest przyjmowane, ale ignorowane — nie zwraca nawet `418` na nieznanym kluczu). Wymagane są wyłącznie `domain`, `fetch_mode`, `keyword_id` i `kid`. > **Ostrzeżenie:** > Endpoint przyjmuje wyłącznie metodę **`POST`**. Oprócz `keyword_id` oraz `kid` wymagane są również **`domain`** i **`fetch_mode`** — pominięcie któregokolwiek z parametrów zwraca `418` z `invalid_data`. Identyfikatory `keyword_id` i `kid` muszą pochodzić z `positions/getData` dla tej samej domeny. ## Odpowiedź Po pomyślnym żądaniu otrzymujesz `data` z obiektem `history_positions`. W przeciwieństwie do `getData` ta odpowiedź **nie zawiera `pagination`** — zwracana jest cała mapa historii. Klucze mapy to daty pomiarów (`RRRR-MM-DD`), a wartości opisują pozycję oraz obecność snippetów SERP w danym dniu. **Skrócona** ```json filename="przykładowa-odpowiedź (skrócona)" { "success": true, "data": { "history_positions": { "2026-05-28": { "position": 29, "has_serp": true } } } } ``` **Pełna** ```json filename="przykładowa-odpowiedź (200)" { "success": true, "data": { "history_positions": { "2026-05-28": { "position": 29, "has_serp": true } } } } ``` ### Struktura odpowiedzi ```ts type PositionsKeywordHistoryResponse = { /** `true` przy powodzeniu; przy błędzie `false` i koperta z `error` */ success: boolean; /** Dane historii pozycji frazy */ data: { /** * Mapa historii pozycji: klucz to data pomiaru (RRRR-MM-DD), * wartość opisuje pozycję oraz obecność snippetów SERP w tym dniu. */ history_positions: Record; }; } export default PositionsKeywordHistoryResponse ``` ## 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"}}}}}`. Analogicznie pominięcie `keyword_id` lub `kid` zwraca `418` z `invalid_data`. ## Powiązane akcje - `getData` — bieżące pozycje fraz (źródło `keyword_id` oraz `kid`) - `getWins` / `getLosses` — frazy, które zyskały / straciły pozycje (taki sam kształt żądania co `getData`) - `getKeywordHistory` — pełna historia pozycji dla pojedynczej frazy (`keyword_id` + `kid` + `domain` + `fetch_mode`) (ta strona)