Dokumentacja API

Sprawdzarka Widoczności AI udostępnia dwa publiczne endpointy JSON. GET /api/report/:domain.json nie wymaga klucza API. POST /api/scan można uwierzytelnić na trzy sposoby — widżetem Turnstile publicznego formularza, darmowym, samodzielnie zakładanym kluczem API klienta lub wewnętrznym tokenem bearer dla bezpośrednich integracji ustawianym przez właściciela strony — zobacz poniżej. Oba endpointy są ograniczone limitami według adresu IP (klucze API klientów dodatkowo mają własny limit per klucz — zobacz „Limity szybkości” i „Uwierzytelnianie” poniżej).

Limity szybkości

  • 8 nowych skanów na adres IP na godzinę (żądania anonimowe / Turnstile)
  • 3 nowe skany na domenę docelową na godzinę
  • 60 nowych skanów na godzinę na jeden samodzielnie założony klucz API klienta — własna pula, nie dzielona z kluczami innych klientów ani z ruchem anonimowym. Zobacz „Uwierzytelnianie” poniżej, jak go zdobyć — jest darmowy.

Wyniki z pamięci podręcznej (do 24 godzin) są zwracane natychmiast i nie liczą się do żadnego z tych limitów.

POST /api/scan

Uruchamia skan lub pobiera zapisany wynik dla domeny.

Uwierzytelnianie

Istnieją trzy sposoby uwierzytelnienia żądania do tego endpointu:

  • Widżet Turnstile (tylko przeglądarka) — publiczny formularz skanowania na tej stronie rozwiązuje niewidoczne wyzwanie Cloudflare Turnstile i wysyła wynikowy turnstileToken w treści żądania. Ta ścieżka działa wyłącznie z prawdziwej przeglądarki wczytującej formularz; nie jest dostępna dla bezpośrednich wywołań API.
  • Darmowy, samodzielnie zakładany klucz API klienta — załóż darmowe konto pod adresem /account/signup, a następnie wygeneruj nazwany klucz API w swoim account dashboard. Wyślij go jako Authorization: Bearer uvk_... i całkowicie pomiń turnstileToken. Każdy klucz dostaje własną pulę limitu 60 skanów/godzinę — wyższą niż anonimowy limit 8/godzinę, i nie dzieloną z kluczami innych klientów ani z ruchem anonimowym. Nie ma żadnej płatności ani niczego do ulepszenia; jedynymi różnicami względem użycia anonimowego są wyższy limit oraz trwały, nazwany, indywidualnie odwoływalny klucz. Klucze są pokazywane w pełni tylko raz, przy tworzeniu, a odwołany klucz natychmiast przestaje działać dla nowych żądań (skan w tle rozpoczęty tuż przed odwołaniem może się jeszcze zakończyć). Rejestracja wymaga tylko adresu e-mail wyglądającego na poprawny oraz hasła o długości co najmniej 12 znaków — nie ma jeszcze weryfikacji e-mail ani procesu resetu hasła (ta aplikacja nie ma obecnie żadnej możliwości wysyłania e-maili transakcyjnych), a sama rejestracja jest chroniona tym samym sprawdzeniem Turnstile i limitami co logowanie administratora.
  • Wewnętrzny PIPELINE_TOKEN (klienci programowi ustawiani przez właściciela strony) — wyślij Authorization: Bearer <token> i całkowicie pomiń turnstileToken. Nie ma samodzielnej rejestracji dla tego tokena — skontaktuj się z właścicielem strony, aby go uzyskać. (Jeśli chcesz po prostu mieć własny klucz już dziś, skorzystaj zamiast tego z darmowej opcji samodzielnej rejestracji powyżej.)

Nie masz tokena? Załóż darmowe konto pod adresem /account/signup aby wygenerować własny klucz API z wyższym limitem (60 skanów/godzinę vs 8/godzinę anonimowo).

Jeśli nagłówek Authorization jest obecny, ale token się nie zgadza — błędny/nieznany PIPELINE_TOKEN, albo samodzielny klucz, który jest nieprawidłowy, nieznany lub odwołany — żądanie kończy się błędem 401 { "error": "Unauthorized" }. Jeśli nagłówek Authorization w ogóle nie zostanie wysłany, zachowanie jest takie jak wcześniej: wymagany jest prawidłowy turnstileToken, w przeciwnym razie żądanie kończy się błędem 403 { "error": "Verification failed. Please retry." }.

Agenci AI lub narzędzia mówiące w MCP mogą pominąć to wszystko i wywołać zamiast tego POST /mcp, który nie wymaga żadnego uwierzytelnienia — zobacz sekcję „MCP server + WebMCP” w README.

Limitowanie szybkości dla wewnętrznego PIPELINE_TOKEN jest takie samo jak dla odwiedzających z przeglądarki: klienci z kluczem dzielą te same limity per IP i per domena docelowa opisane powyżej, więc intensywne użycie programowe może wciąż trafić na limit per IP. Samodzielnie zakładane klucze API klientów działają inaczej — każdy klucz ma własną pulę 60/godzinę (zobacz „Limity szybkości” powyżej), niezależną od adresu IP wywołującego.

Treść żądania

{
  "url": "example.com",
  "forceRescan": false
}

Odpowiedzi

Status Treść Znaczenie
200 ScanRecord Trafienie w pamięci podręcznej — wynik jest już świeży (do 24 godz.).
202 { "domain": "example.com" } Skan uruchomiony w tle — odpytuj GET /api/report/:domain.json, aż zwróci 200.
400 { "error": "..." } Błędny lub nierozwiązywalny adres URL.
401 { "error": "Unauthorized" } Wysłano nagłówek Authorization: Bearer, ale token się nie zgadzał.
403 { "error": "Verification failed. Please retry." } Nie wysłano nagłówka Authorization, a sprawdzenie Turnstile nie powiodło się lub turnstileToken był brakujący/nieprawidłowy.
429 { "error": "...", "retryAfterSeconds": N } Przekroczono limit szybkości. Poczekaj retryAfterSeconds przed ponowną próbą.

Przykład curl

curl -X POST https://aivisibility.unomage.pl/api/scan \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"url":"example.com"}'

Pomiń nagłówek Authorization tylko wtedy, gdy wywołujesz ten endpoint z przeglądarki, która już dostarcza token Turnstile w treści żądania — bezpośredni/skryptowi klienci potrzebują tokena bearer pokazanego powyżej. YOUR_TOKEN może być zarówno samodzielnym kluczem API uvk_... z panelu konta, jak i wewnętrznym PIPELINE_TOKEN — oba są akceptowane w ten sam sposób.

GET /api/report/:domain.json

Pobiera pełny ScanRecord dla domeny. Zwraca 404, jeśli domena nigdy nie była skanowana.

Odpowiedzi

Status Treść Znaczenie
200 ScanRecord Pełny zapis dla domeny.
404 { "error": "Not found" } Domena nie została jeszcze zeskanowana.

Przykład curl

curl https://aivisibility.unomage.pl/api/report/example.com.json

Kształt ScanRecord

{
  "domain": "example.com",
  "status": "ok" | "failed",
  "scannedAt": "ISO 8601 string",
  "result": {
    "score": 0-100,
    "grade": "A" | "B" | "C" | "D" | "F",
    "label": "string",
    "pillars": [
      {
        "id": "string",
        "title": "string",
        "score": 0-100,
        "points": 0-100,
        "weight": 0-100,
        "signals": [ /* see below */ ]
      }
    ],
    "topIssues": [
      {
        "id": "string",
        "title": "string",
        "status": "fail" | "warn",
        "impact": "critical" | "high" | "medium" | "low",
        "detail": "string",
        "fix": {
          "what": "string",
          "why": "string",
          "how": "string",
          "effort": "S" | "M" | "L"
        }
      }
    ]
  } | null,
  "offSite": {
    "wikidata":    { "status": "found" | "not_found" | "unknown", "detail": "string", "url": "string | null" },
    "wikipedia":   { "status": "found" | "not_found" | "unknown", "detail": "string", "url": "string | null" },
    "commonCrawl": { "status": "found" | "not_found" | "unknown", "detail": "string", "url": "string | null" }
  } | null
}

result to null, gdy status ma wartość "failed". offSite to null dla skanów wykonanych zanim dodano sprawdzanie sygnałów zewnętrznych, lub gdy samo sprawdzenie się nie powiodło.

Wzorzec odpytywania

Gdy POST /api/scan zwróci 202, skan działa w tle. Odpytuj GET /api/report/:domain.json co 1–2 sekundy, aż zwróci 200:

# 1. Start the scan
curl -s -X POST https://aivisibility.unomage.pl/api/scan \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"url":"example.com"}' | jq .

# 2. Poll until ready (bash loop)
while true; do
  result=$(curl -s https://aivisibility.unomage.pl/api/report/example.com.json)
  echo "$result" | jq '.status' && break || sleep 2
done