Przejdź do treści

API dla agentów AI

Jak agent AI, skrypt albo narzędzie do automatyzacji korzysta z API AskAnieli krok po kroku: klucz, jedna strona, audyt witryny, intencja wyszukiwania, koszty, błędy i JSON wyników.

Każdy przykład z tej strony przed publikacją uruchomiliśmy na naszym API stagingowym. Wersja Markdown tej strony: https://docs.askaniela.com/pl/user/agents.md.

Dla kogo

  • Agenci AI z narzędziem HTTP (Claude, ChatGPT, Codex, Cursor i podobne): daj agentowi tę stronę, przykładowy prompt systemowy i klucz w zmiennej środowiskowej.
  • Skrypty (Python, Node, shell): skopiuj przykłady curl albo Python.
  • Narzędzia do automatyzacji (n8n, Make, Zapier): węzeł HTTP Request z Authorization: Bearer gsj_..., węzeł Wait i pętla po polu statusu.
  • MCP: serwer MCP AskAnieli jest planowany nad tym samym API, z tymi samymi kluczami i limitami. Do tego czasu podłącz API jako narzędzie HTTP albo wygeneruj narzędzia z openapi.json (zob. Co czytają agenci).

Przed pierwszym wywołaniem

Co Wartość
Adres bazowy https://api.askaniela.com
Nagłówek Authorization: Bearer gsj_... w każdym żądaniu (bez klucza: 401 unauthorized)
Treść JSON, Content-Type: application/json
Klucz klucz projektu z zakładki Klucze API projektu (Klucze API)
Zakresy judge, reports:read, jobs (domyślne) wystarczą do wszystkiego na tej stronie

Klucze utworzone przed zmianą domyślnych zakresów (październik 2026) mogą nie mieć jobs. Wtedy audyty witryny zwracają 403 insufficient_scope z error.details.required_scope; utwórz nowy klucz z domyślnymi zakresami. Daj każdemu agentowi osobny klucz z datą wygaśnięcia, trzymaj go w zmiennej środowiskowej i nigdy nie wklejaj go do promptu, logu ani czatu.

export ASKANIELA_URL=https://api.askaniela.com
export ASKANIELA_API_KEY=gsj_...

Mapa zadań

Zadanie Wywołanie Zakres Odpowiedź Płatne
Sprawdź jedną stronę POST /v1/judge judge 200, raport w treści (1-3 min) tak
Sprawdź do 10 stron POST /v1/judge/batch judge 200, results[] tak
Cena audytu witryny POST /v1/audits/site/preview, potem /estimate jobs 200 nie
Audyt witryny POST /v1/audits/site jobs 202, potem odpytywanie tak
Stan audytu GET /v1/audits/{id} reports:read 200 nie
Wyniki audytu GET /v1/audits/{id}/export.json reports:read 202 w przygotowaniu, potem 200 nie
Plan poprawek GET /v1/audits/{id}/fix-plan?format=md reports:read 202 w trakcie generowania, potem Markdown nie
Intencja wyszukiwania POST /v1/intent judge 202, potem GET /v1/intent/{id} tak
Saldo i limity GET /v1/usage dowolny 200 nie
Ceny GET /v1/tiers bez klucza 200 nie

1. Sprawdź jedną stronę

curl -s "$ASKANIELA_URL/v1/judge" \
  -H "Authorization: Bearer $ASKANIELA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/"}' \
  --max-time 300 -D headers.txt -o report.json
grep -i x-cost-usd headers.txt     # x-cost-usd: 0.0665
  • Wyślij dokładnie jedno z: url, html albo text. Opcjonalnie: modes (["spam"], ["quality"], ["helpful"] albo kilka; mniej trybów = taniej), rules (id z GET /v1/rules), render_js, explain (dowody i poprawki dla trafień), report_lang (en albo pl), project_id.
  • Wywołanie jest synchroniczne. Jedna strona z pełnym katalogiem trwała na stagingu około 2 minut; mniej modes = szybciej. Ustaw limit czasu odczytu klienta na co najmniej 300 sekund.
  • Odpowiedź nie zawiera id raportu. Zapisany raport znajdziesz przez GET /v1/reports?url=https://example.com/&limit=1 (id = rep_…), potem GET /v1/reports/{id}/fix-plan?format=md.
  • Więcej niż jedna strona: POST /v1/judge/batch z {"items": [{"url": …}, …]} (do 10) albo audyt witryny.

2. Audyt witryny

Audyt witryny sprawdza próbę stron z sitemapy albo z Twojej listy URL-i. Działa w tle.

Krok 1: podgląd (bezpłatny). Znajduje sitemapę i grupuje URL-e we wzorce.

curl -s "$ASKANIELA_URL/v1/audits/site/preview" \
  -H "Authorization: Bearer $ASKANIELA_API_KEY" -H "Content-Type: application/json" \
  -d '{"site": "example.com"}'
# {"preview_id": "7963…", "total": 94, "patterns": [{"pattern": "/user/<slug>", "count": 11, …}], …}

Krok 2: wycena (bezpłatna, nic się nie uruchamia). Wyślij treść, którą chcesz zlecić, z preview_id.

curl -s "$ASKANIELA_URL/v1/audits/site/estimate" \
  -H "Authorization: Bearer $ASKANIELA_API_KEY" -H "Content-Type: application/json" \
  -d '{"site": "example.com", "preview_id": "7963…", "pages": 5,
       "scope": {"include_patterns": ["/user/<slug>"]}}'
# {"selected": 11, "pages": 5, "rules": 119, "cost_usd": 0.3325, "cost_per_page_usd": 0.0665, "seconds": 50, …}

Krok 3: zapytaj człowieka. Pokaż cost_usd, pages i czas, poczekaj na zgodę. Agent nigdy nie powinien uruchamiać audytu sam z siebie.

Krok 4: zlecenie (płatne). Wyślij tę samą treść jeden raz.

curl -s "$ASKANIELA_URL/v1/audits/site" \
  -H "Authorization: Bearer $ASKANIELA_API_KEY" -H "Content-Type: application/json" \
  -d '{"site": "example.com", "preview_id": "7963…", "pages": 5,
       "scope": {"include_patterns": ["/user/<slug>"]}}'
# 202 {"audit_id": "aud_2fptzm5h3hiruh6c", "job_id": "job_e74cap43wdgzyszz", "pages": 5, "patterns": 1}

Nie powtarzaj tego POST po przekroczeniu czasu: najpierw poszukaj audytu w GET /v1/audits?limit=5 (zob. Bezpieczne ponawianie).

Krok 5: czekaj. Odpytuj GET /v1/audits/{audit_id} co 15-30 sekund, aż progress.status będzie końcowy. Ten endpoint nie wysyła Retry-After, więc odstęp dobierz sam; eta_seconds podaje przewidywany czas.

curl -s "$ASKANIELA_URL/v1/audits/aud_2fptzm5h3hiruh6c" -H "Authorization: Bearer $ASKANIELA_API_KEY"
# {"progress": {"status": "running", "total": 5, "done": 1, "failed": 0, …}, "eta_seconds": 38, …}
progress.status Końcowy Co robić
queued, running nie odpytuj dalej
pausing, paused, cancelling nie ktoś wstrzymał albo zatrzymał audyt; POST /v1/audits/{id}/resume wznawia wstrzymany
done tak pobierz wyniki; failed > 0 znaczy, że części stron nie udało się sprawdzić
failed tak audyt przerwany (error); nieocenione strony wracają do salda
cancelled tak zatrzymany na stałe; ocenione strony zachowują raporty

Audyt 5 stron z przykładu trwał na stagingu około 6 minut. Te same 8 stanów i przejścia opisuje Stany zadań.

Zamiast odpytywać, możesz dostać webhook. Audyt nie ma pola webhook_url; właściciel albo admin organizacji raz zakłada webhook organizacji, który dostaje job.finished z job_id audytu. Agent, który ma tylko klucz, powinien odpytywać.

Krok 6: wyniki. export.json przygotowuje się w tle: pierwsze żądanie może zwrócić 202 {"status": "pending", "retry_after": 5} z nagłówkiem Retry-After. Odczekaj tyle sekund i powtórz GET.

curl -s "$ASKANIELA_URL/v1/audits/aud_2fptzm5h3hiruh6c/export.json" -H "Authorization: Bearer $ASKANIELA_API_KEY"

Krok 7: plan poprawek w Markdown, gotowy dla człowieka albo innego agenta. Przy pierwszym żądaniu to samo 202 + Retry-After; kolejne czytają zapisany plan bez opłaty. Język planu: report_lang audytu, a bez niego nagłówek Accept-Language.

curl -s "$ASKANIELA_URL/v1/audits/aud_2fptzm5h3hiruh6c/fix-plan?format=md" -H "Authorization: Bearer $ASKANIELA_API_KEY"
# # Fix plan: example.com
# Source: site audit aud_2fptzm5h3hiruh6c · Generated: 2026-10-20 20:12 UTC

Dostępne też: export.zip (plik Markdown na stronę plus audit.json), export.csv, export.html, export.pdf i fix-plan?format=json.

3. Intencja wyszukiwania dla frazy

curl -s "$ASKANIELA_URL/v1/intent?wait=60" \
  -H "Authorization: Bearer $ASKANIELA_API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "best running shoes", "market": "en-US"}'
# 202 {"id": "itr_…", "status": "running", "tier": "basic", "price_usd": 0.0015, "report": null, …}
  • Odpowiedź to 202 ze status queued, running, done albo failed. ?wait=N (do 60) czeka na wynik; jeśli nie jest gotowy, odpytuj GET /v1/intent/{id} co 15 sekund do done albo failed.
  • price_usd to opłata za tę frazę. Jest niższa, gdy można użyć świeżych wyników wyszukiwania (freshness: auto, domyślnie); fresh zawsze pobiera nowe wyniki za pełną cenę.
  • tier: basic (intencja i najlepsza forma strony), premium (Ani czyta też czołowe strony) albo compare (Twoja strona z compare_url obok nich). Ceny: GET /v1/tiers (intent[]).
  • Wiele fraz: POST /v1/intent/batch (JSON items) albo POST /v1/intent/batch/csv.

Koszty i limity

  • Cena przed zleceniem: audyt witryny ma POST /v1/audits/site/estimate; ceny stron i intencji są w GET /v1/tiers i w Saldo i cennik.
  • Koszt wywołania: każda płatna odpowiedź ma nagłówek X-Cost-USD (np. 0.0665 za stronę z pełnym katalogiem, 0.0315 za sam spam). Dla audytów i zadań to kwota zarezerwowana na starcie; nieocenione strony wracają później.
  • Saldo: GET /v1/usage pokazuje zużycie dnia i miesiąca, limit i saldo w USD.
  • Limit wyczerpany: 429 quota_exceeded z details (limit_usd, used_usd, requested_usd, remaining_usd). API nie używa 402; brak salda to zawsze 429 quota_exceeded. Zatrzymaj się i powiedz człowiekowi; ponawianie nic nie da.
  • Za dużo żądań: 429 rate_limited z Retry-After i nagłówkami RateLimit-*. Odczekaj i ponów.
  • Praca w toku: naraz działają najwyżej 2 audyty albo zadania na organizację (429 too_many_active_jobs). Poczekaj, aż któreś się skończy.

Błędy

Każdy błąd z /v1/* ma jeden kształt. Rozgałęziaj po code, nigdy po message.

{"error": {"code": "unknown_rule", "message": "Unknown rules: NOPE",
           "details": {"rules": ["NOPE"]}, "request_id": "37da8d48f0e74f579f984e1e1cf215e1"}}

message jest po angielsku; z nagłówkiem Accept-Language: pl po polsku. code się nie zmienia.

HTTP code Co robi agent
400 unknown_rule, rule_disabled, invalid_url, invalid_webhook_url popraw wejście; nie ponawiaj bez zmian
401 unauthorized, invalid_api_key, api_key_expired zatrzymaj się i poproś o ważny klucz
403 insufficient_scope zatrzymaj się; człowiek tworzy klucz z details.required_scope
403 ip_not_allowed, org_suspended, forbidden zatrzymaj się i powiedz człowiekowi
404 report_not_found, audit_not_found, job_not_found, intent_not_found sprawdź id (rep_, aud_, job_, itr_)
409 job_not_controllable, audit_running, upgrade_unavailable stan nie pozwala na tę akcję; odczytaj status
413 batch_too_large, audit_too_large, item_too_large podziel pracę albo użyj audytu witryny zamiast wsadu
422 validation_error popraw treść; details[] wymienia pola
422 sitemap_not_found, empty_selection, preview_expired, invalid_scope zmień źródło albo zakres; zrób podgląd jeszcze raz
429 rate_limited, too_many_active_jobs odczekaj Retry-After sekund i ponów
429 quota_exceeded zatrzymaj się; limit albo saldo wyczerpane
502 fetch_failed nie udało się pobrać strony; powiedz człowiekowi, nie ponawiaj w pętli
502 inference_failed żadnej reguły nie oceniono, bez opłaty; ponów raz później
503 spend_cap_reached, beta_budget_reached, queue_unavailable, unavailable odczekaj Retry-After (często 3600 s)
503 fix_plan_unavailable, export_unavailable bez opłaty; ponów GET później

502 albo 504 bez treści JSON pochodzi z bramy, np. w trakcie wdrożenia. GET ponów po 30 sekundach. POST nie ponawiaj w ciemno (następna sekcja). Każda odpowiedź ma X-Request-ID; podaj go przy zgłoszeniu problemu. Wszystkie kody: Błędy.

Bezpieczne ponawianie

API nie ma jeszcze Idempotency-Key, więc powtórzony POST to nowa praca i nowa opłata.

  • GET można powtarzać zawsze.
  • POST /v1/judge: powtórka sprawdza i nalicza stronę jeszcze raz. Po przekroczeniu czasu najpierw szukaj raportu w GET /v1/reports?url=…&limit=1.
  • POST /v1/audits/site, POST /v1/jobs: po przekroczeniu czasu albo błędzie bramy sprawdź GET /v1/audits?limit=5 albo GET /v1/jobs?limit=5. Audyt zwykle już tam jest.
  • POST /v1/intent: sprawdź GET /v1/intent?q=<fraza>&limit=5. Fraza, która utknęła w running, zostaje po około 40 minutach zamknięta jako failed ze zwrotem; nie zlecaj jej ponownie wcześniej.
  • Wysyłaj własny X-Request-ID ([A-Za-z0-9._-]{1,128}), żeby łączyć żądania z własnymi logami.

Jak czytać wyniki

Jedna strona (POST /v1/judge, GET /v1/reports/{id})

Pole Znaczenie
violations[] reguły polityk spamu
quality_signals[] reguły jakości strony i treści pomocnych
positives[], labels[], choices[] sygnały pozytywne, etykiety kontekstu (np. temat YMYL) i skale ocen
not_assessed[] polityki, których nie da się ocenić z jednej strony, z reason
skipped[] id reguł pominiętych przy wybranych modes albo rules
fetch, extraction_ok, truncated jak odczytano stronę; extraction_ok: false = mało treści głównej

Każda reguła ma rule_id, policy, layer, kind, ok (false = reguły nie udało się ocenić, zob. error) i score_raw od 0 do 1. Siła sygnału = round(score_raw * 100), od 0 do 100: 80 i więcej to silny, 50-79 średni, poniżej 50 niski. Pokazuj ją jako „sygnał 87 na 100”. To nie jest procent, prawdopodobieństwo ani decyzja Google. Przy explain: true trafienia dostają evidence.quotes[] (text, verified: kod znalazł cytat na stronie) i evidence.fix. Trafienie z unsupported: true nie ma zweryfikowanego cytatu i wymaga sprawdzenia przez człowieka. Pomijaj pola wewnętrzne z, coverage, top1_other, probability, entropy, samples, spread i prompt_sha; mogą się zmienić.

Audyt witryny (GET /v1/audits/{id}/export.json, schema_version 1.1)

Eksport zawiera tylko potwierdzone trafienia. Przykładowy kształt (jedno trafienie, skrócone):

{
  "schema_version": "1.1",
  "audit": {"id": "aud_…", "status": "done", "pages_total": 5, "pages_checked": 5, "pages_failed": 0,
            "pages_with_findings": 1, "site_levels": {"spam": "high", "quality": "low", "helpful": "low"},
            "note": "1 of 5 pages (20%) have a confirmed spam finding. …"},
  "pages": [{
    "report_id": "rep_…", "url": "https://example.com/best-deals", "pattern": "/<slug>", "risk": "high",
    "findings": 1, "spam_level": "high", "quality_level": "low", "helpful_level": "na",
    "items": [{
      "category": "spam", "rule_id": "SP-AFF", "policy": "Thin affiliation", "title": "…", "level": "high",
      "signal": 91, "evidence": [{"text": "…cytat ze strony…", "verified": true}],
      "fix": "…co zmienić na tej stronie…", "fix_personal": true,
      "sources": [{"label": "…", "url": "https://developers.google.com/search/docs/essentials/spam-policies#thin-affiliate-pages"}]
    }]
  }]
}
  • site_levels wynikają z udziału stron z potwierdzonym trafieniem: poniżej 2% niski, 2-10% średni, powyżej 10% wysoki.
  • Poziomy strony: high, medium, low, na (kryteria nie mają zastosowania, np. strona użytkowa) albo unknown.
  • risk to najwyższy potwierdzony poziom strony: high, medium albo none.
  • signal jest już w skali 0-100. fix_personal: true znaczy, że poprawkę napisano dla tej strony; inaczej to ogólna rada reguły. sources to oficjalne wytyczne Google, na których opiera się reguła.

Przykład w Pythonie

Wymaga httpx (pip install httpx). Sprawdza jedną stronę, wycenia audyt i pokazuje, gdzie go zlecić i śledzić. Komentarze w kodzie są po angielsku, jak w wersji angielskiej strony.

"""AskAniela API from Python (httpx): one page, a site audit, results and costs."""

import os
import time

import httpx

API = os.environ.get("ASKANIELA_URL", "https://api.askaniela.com")
KEY = os.environ["ASKANIELA_API_KEY"]
FINAL = {"done", "failed", "cancelled"}

client = httpx.Client(
    base_url=API,
    headers={"Authorization": f"Bearer {KEY}"},
    timeout=httpx.Timeout(15.0, read=300.0),  # one page takes up to a few minutes
)


class AnielaError(Exception):
    def __init__(self, status: int, code: str, message: str, retry_after: str | None, request_id: str | None):
        super().__init__(f"{status} {code}: {message} (request_id={request_id})")
        self.status, self.code, self.retry_after, self.request_id = status, code, retry_after, request_id


def call(method: str, path: str, **kw) -> httpx.Response:
    r = client.request(method, path, **kw)
    if r.status_code >= 400:
        is_json = r.headers.get("content-type", "").startswith("application/json")
        err = r.json().get("error", {}) if is_json else {}  # a 502/504 from a proxy has no JSON body
        raise AnielaError(r.status_code, err.get("code", f"http_{r.status_code}"), err.get("message", r.text[:200]),
                          r.headers.get("Retry-After"), err.get("request_id"))
    return r


def cost(r: httpx.Response) -> float:
    return float(r.headers.get("X-Cost-USD", "0"))


def wait_ready(path: str, params: dict | None = None, max_wait: int = 900) -> httpx.Response:
    """GET that may answer 202 + Retry-After while a file is prepared. Repeating a GET is safe."""
    deadline = time.monotonic() + max_wait
    while True:
        r = call("GET", path, params=params)
        if r.status_code != 202:
            return r
        if time.monotonic() > deadline:
            raise TimeoutError(path)
        time.sleep(int(r.headers.get("Retry-After", "10")))


def judge_page(url: str) -> tuple[dict, float]:
    r = call("POST", "/v1/judge", json={"url": url, "modes": ["spam"]})
    return r.json(), cost(r)


def estimate_site_audit(site: str, pages: int) -> dict:
    body = {"site": site, "pages": pages}
    preview = call("POST", "/v1/audits/site/preview", json=body).json()
    body["preview_id"] = preview["preview_id"]
    return {"body": body, "estimate": call("POST", "/v1/audits/site/estimate", json=body).json()}


def start_site_audit(body: dict) -> str:
    """Paid. Call once, after the user accepted the estimate. Never retry this POST blindly."""
    return call("POST", "/v1/audits/site", json=body).json()["audit_id"]


def follow_audit(audit_id: str, every: int = 20) -> tuple[dict, str]:
    while True:
        a = call("GET", f"/v1/audits/{audit_id}").json()
        p = a["progress"]
        print(f"{p['status']}: {p['done']}/{p['total']} pages, failed {p['failed']}")
        if p["status"] in FINAL:
            break
        time.sleep(every)
    export = wait_ready(f"/v1/audits/{audit_id}/export.json").json()
    plan = wait_ready(f"/v1/audits/{audit_id}/fix-plan", params={"format": "md"}).text
    return export, plan


def strongest(report: dict) -> list[tuple[str, int]]:
    """Spam and quality rules with signal strength 0-100 (score x 100), strongest first."""
    rows = [(r["rule_id"], round(r["score_raw"] * 100))
            for key in ("violations", "quality_signals") for r in report[key] if r.get("ok")]
    return sorted(rows, key=lambda x: -x[1])


if __name__ == "__main__":
    print(call("GET", "/v1/usage").json()["org"]["month"])
    report, usd = judge_page("https://example.com/")
    print("cost", usd, "top rules", strongest(report)[:3])
    plan = estimate_site_audit("example.com", pages=5)
    print("estimate", plan["estimate"]["cost_usd"], "USD,", plan["estimate"]["seconds"], "s")
    # audit_id = start_site_audit(plan["body"])  # only after the user said yes
    # export, fix_plan_md = follow_audit(audit_id)

Przykładowy prompt systemowy

Wklej do instrukcji agenta i dostosuj limity. Prompt jest po angielsku, bo modele i narzędzia najczęściej pracują w tym języku; możesz go przetłumaczyć.

You can use the AskAniela API at https://api.askaniela.com to check web pages against Google spam policies
and page-quality guidelines. The API key is in the environment variable ASKANIELA_API_KEY; send it as
"Authorization: Bearer <key>". Never print, log or repeat the key.

Rules:
1. Check only sites the user owns or is authorised to analyse.
2. Before any paid call, get the price: POST /v1/audits/site/estimate for site audits, GET /v1/tiers for single
   pages and search intent. Tell the user the price and wait for an explicit yes. Never start a site audit on
   your own. Single pages up to $0.10 in total per conversation do not need a separate yes.
3. Never repeat a POST that creates work (judge, audits/site, jobs, intent) without checking first whether the
   first one went through (GET /v1/reports?url=…, /v1/audits?limit=5, /v1/intent?q=…). A repeat is charged again.
4. Repeating GET requests is safe. On 202 wait for Retry-After seconds. Poll audit status every 20-30 seconds.
5. Branch on error.code, never on the message. Stop and ask the user on 401, 403, quota_exceeded and fetch_failed.
   Wait Retry-After on rate_limited, too_many_active_jobs and 503 codes.
6. Report results as signal strength from 0 to 100 (score_raw x 100, or "signal" in exports): "signal 87 of 100".
   Never present it as a percentage, a probability or a Google penalty. Say "may break the policy" or
   "possible quality issue", not "violates".
7. Quote evidence only when verified is true. Use the fix plan (GET /v1/audits/{id}/fix-plan?format=md) for
   recommendations instead of inventing your own.
8. After every paid call, read the X-Cost-USD header and keep a running total for the user.
Docs for agents: https://docs.askaniela.com/llms.txt and https://docs.askaniela.com/user/agents.md

Co mówią agentom llms.txt i openapi.json

Adres Co daje
https://docs.askaniela.com/llms.txt spis wszystkich stron dokumentacji jako linki Markdown z jednozdaniowym opisem (format llms.txt)
https://docs.askaniela.com/llms-full.txt wszystkie strony dokumentacji w jednym pliku Markdown
https://docs.askaniela.com/<strona>.md dowolna strona jako czysty Markdown, np. https://docs.askaniela.com/pl/user/agents.md; strony polskie pod /pl/
https://api.askaniela.com/llms.txt krótki spis na hoście API: linki do dokumentacji i adres OpenAPI
https://api.askaniela.com/openapi.json aktualny opis API w OpenAPI 3.1

Znane braki openapi.json, które uzupełnia ta strona:

  • Nie deklaruje jeszcze klucza Bearer gsj_...; podaje cookie sesji i logowanie hasłem. Agenci i generatory narzędzi powinni je pominąć i wysyłać Authorization: Bearer gsj_....
  • Nie ma przykładów żądań, błędy opisuje tylko jako 4XX/5XX, a nagłówków X-Cost-USD i Retry-After nie deklaruje. Korzystaj z tabeli Błędy i kroków powyżej.
  • Zawiera też operacje konta, sesji i administracji. Udostępniaj agentowi tylko operacje z mapy zadań.

Dalej: Szybki start API, Klucze API, Przewodnik po audytach witryny, Webhooki i zadania, Błędy.