Fejlesztői

API & Integráció

A GEOscore Next.js App Router alatt fut, az API route-ok REST-es POST végpontok. Az alábbiak a src/app/api/ alatt élnek.

POST /api/scan

Anonim scan végpont. Egyetlen domain auditja, eredmény mentve a scan_results táblába.

Request body:

{
  "domain": "kovacsbolt.hu",
  "private": false  // V15: opcionális, default false. Ha true → kihagyva sitemap-ből
}

Response (200):

{
  "id": "uuid",                    // scan_results.id, későbbi /results/{id}-hez
  "url": "https://kovacsbolt.hu",
  "scores": { "overall": 72, "grade": "B", "categories": {...} },
  "checks": [...],                 // ~30 GeoCheck objektum
  "schemas": ["Organization", "FAQPage"],
  "crawlerAccess": { "allowed": [...], "blocked": [...] },
  "aiTests": [...],                // 4 AITestResult
  "lighthouse": { "performanceScore": 87, "lcp": 2.1, ... },
  "actionPlan": [...],             // priorizált javítási roadmap
  "remaining": 4,                  // hátralévő scan-ek tier szerint
  "cached": false                  // ha 24h-n belül futott már: true
}

POST /api/scan-with-competitors (V9 — új)

N+1 párhuzamos scan, percentile- és gap-alapú összehasonlítás. Auth-only — a rate-limit költség miatt csak bejelentkezett user érheti el. Max 3 versenytárs (Vercel timeout védelem).

Request body:

{
  "domain": "fő-domain.hu",
  "competitors": ["versenytars1.hu", "versenytars2.hu", "versenytars3.hu"]
}

Response:

{
  "id": "uuid",
  "main": { "domain": "...", "result": {...}, "score": 72, "grade": "B" },
  "competitors": [
    { "domain": "...", "score": 68, "grade": "C", "isMain": false },
    ...
  ],
  "benchmark": {
    "ranking": [{ "position": 1, "domain": "...", "score": 75, "isMain": false }, ...],
    "mainRank": 2,
    "totalRanked": 4,
    "percentile": 67,           // százalékos pozíció a versenytársak között
    "gapVsAverage": 4,          // pontkülönbség a versenytársak átlagához képest
    "averageCompetitor": 68,
    "verdict": "A fő domain 4 ponttal a versenytársak átlaga felett."
  }
}

A V9 endpoint a kompetitor scan-eket automatikusan is_public: false-ra menti — más cégek domain-jeit nem indexeljük publikusan.

POST /api/audit (auth-only)

Bejelentkezett user audit végpontja, magasabb rate-limittel. Kéri az auth header-t (Authorization: Bearer <jwt>), a tier-szerinti rate-limit alkalmazódik.

Webhook (V14 — retry + idempotency)

Ha az admin felületen beállítasz egy WEBHOOK_URL-t, minden scan végén fire-and-forget POST megy oda. A V14 frissítés óta retry-zik (3x exponential backoff: 1s, 2s, 4s) és idempotency-key-t is küld.

Headers:

Content-Type: application/json
X-Idempotency-Key: <scan_uuid>     // V14: dedup-key a retry-ok ellen

Body (generic):

{
  "domain": "kovacsbolt.hu",
  "score": 72,
  "grade": "B",
  "topIssues": ["Hiányzó FAQ schema", "Nincs sitemap"],
  "resultsLink": "https://geoscore.hu/results/uuid",
  "categories": { "Technical": 80, "Content": 70, ... },
  "summary": { "pass": 12, "warning": 5, "error": 3 }
}

A webhook automatikusan formázott Slack-block / Discord-embed payload-ot küld, ha az URL hooks.slack.com vagy discord.com/api/webhooks. Egyébként a fenti generikus JSON.

Retry logika: 5xx, 408 timeout, 429 rate-limit, vagy network hibára 3-szor próbálkozunk (1s, 2s, 4s delay). 4xx (kivéve 408/429) → permanent error, nem retry-zünk. Az idempotency-key biztosítja, hogy a fogadó oldal felismerje a duplikátumot és ne dolgozza fel kétszer.

Rate-limit tier-ek

TierScan / napMegjegyzés
Anonymous5IP-alapú, VPN-nel kerülhető
Free (auth)5Auth user_id alapján
Basic10
Pro30
Agency100Multi-domain dashboardhoz ideális

A rate-limit napi (UTC midnight reset). 24h cache: ugyanaz a domain+IP páros 24h-n belül cache-elt választ kap, nem fogyaszt új scan-keretet. A V9 kompetitor-benchmark N+1 scan-t számít fel egyszerre, tehát 4 domain × 1 lekérés = 4 scan a tier-edből.

V15 — Privát eredmény-flag (GDPR)

GDPR-érzékeny ügyfeleknél (pl. egy ügynökség sales-funnel-céllal scan-elt egy potenciális ügyfelet) az eredmény ne kerüljön a publikus sitemap-be. A scan body-ban add át:

POST /api/scan
{
  "domain": "ugyfel-jelolt.hu",
  "private": true
}

A scan_results.is_public oszlop false-ra állítódik. A /sitemap.xml query WHERE is_public = true szűrővel fut, így a privát eredmény URL-jét nem indexeljük. Az eredmény-oldal (/results/{id}) továbbra is elérhető direct linkkel — csak nincs benne a sitemap-ben.

További endpoint-ok (csak referenciaként)

  • GET /api/results/[id] — egy konkrét scan-eredmény lekérése
  • POST /api/leads — lead form submit (név + email + domain)
  • POST /api/dashboard/rescan — dashboard rescan (auth)
  • POST /api/dashboard/domains — új domain hozzáadása (auth)
  • PATCH /api/dashboard/settings — user beállítások (email_notifications)
  • POST /api/cron/email-drip — éjszakai drip email cron
  • GET /api/unsubscribe — RFC 8058 List-Unsubscribe