5 Adımda Entegrasyon
- API anahtarı oluştur
Kayıt olup giriş yapın, sidebar'daki Seo Analiz Aracı API Key Oluşturma menüsüne tıklayın: https://www.spindorai.com/seo-analizi-api-key (ücretsiz hesap). Anahtar formatı:
sp_seo_…— tam değer yalnızca bir kez gösterilir. - POST https://www.spindorai.com/api/public-seo-analizi/analyze
Header:
Content-Type: application/json,X-Spindora-Key: sp_seo_…Gövde:
{"url":"https://example.com","keywords":[],"device":"desktop","locale":"tr"} - task_id kaydet
Yanıt örneği aşağıda (JSON Yanıt Örnekleri).
- GET https://www.spindorai.com/api/public-seo-analizi/result/{task_id}
Aynı API key ile 2 saniyede bir poll et. 202 = bekliyor, 200 = sonuç hazır. Önerilen max bekleme: ~2 dakika (60 deneme).
- Attribution göster
Sonuçların yanında zorunlu: Powered by Spindora → https://www.spindorai.com
Genel Bakış
Spindora SEO Analiz API, herhangi bir URL için on-page SEO denetimi yapar: başlık, meta, H1 yapısı, kelime sayısı, schema, outbound linkler, sunucu zamanlaması ve daha fazlası. İstekler asenkron işlenir — önce analiz kuyruğa alınır, ardından task_id ile sonuç poll edilir.
API key zorunlu
Harici isteklerde
30 analiz / gün
Anahtar başına
Attribution
Zorunlu link
Kimlik Doğrulama
Harici entegrasyonlar için geçerli bir API anahtarı zorunludur. Anahtarı panelden oluşturun; tam değer yalnızca oluşturma anında gösterilir.
| Yöntem | Değer |
|---|---|
| Header (önerilen) | X-Spindora-Key: sp_seo_… |
| Bearer | Authorization: Bearer sp_seo_… |
Anahtar oluşturma: www.spindorai.com/seo-analizi-api-key (giriş gerekli)
Kota & Limitler
- API anahtarı başına günde 30 analiz.
- Kullanıcı başına en fazla 3 aktif anahtar.
- API yanıtlarında screenshot döndürülmez — yalnızca www.spindorai.com web arayüzünde mevcuttur.
İstek Akışı
POST /analyze
Analizi kuyruğa al, task_id al
GET /result/{id}
~2 sn aralıkla poll et
200 OK
JSON sonuç hazır
202 = bekliyor · 200 = hazır
İstek Şeması
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
| url | string | Evet | Analiz edilecek tam URL (https://…) |
| keywords | string[] | Hayır | Max 3 anahtar kelime |
| device | "desktop" | "mobile" | Hayır | Varsayılan: desktop |
| locale | "tr" | "en" | Hayır | Kontrol mesajlarının dili |
Uç Noktalar
/analyzeAnalizi başlatır.
{
"url": "https://example.com",
"keywords": ["seo", "kelime"],
"device": "desktop",
"locale": "tr"
}Yanıt: { "task_id": "...", "mode": "api", "attribution": { ... } }
/result/{task_id}Aynı API anahtarı ile poll edin. Hazır olduğunda tam JSON döner (screenshots boş).
/quotaWeb arayüzü IP kotası (harici API için değil).
JSON Yanıt Örnekleri
Gerçek entegrasyonda bu yapıları bekleyin. screenshots her zaman boş dizidir.
POST /analyze → 200
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "Analiziniz sıraya alındı. Lütfen bekleyin…",
"mode": "api",
"attribution": {
"text": "Powered by Spindora",
"url": "https://www.spindorai.com",
"required": true,
"html": "<a href=\"https://www.spindorai.com\" target=\"_blank\" rel=\"noopener\">Powered by Spindora</a>"
}
}GET /result/{task_id} → 202 (bekliyor)
{ "status": "pending" }GET /result/{task_id} → 200 (hazır, kısaltılmış)
{
"success": true,
"url": "https://example.com",
"final_url": "https://example.com/",
"device": "desktop",
"keywords": ["seo"],
"seo_score": 78,
"word_count": 1240,
"title_text": "Example Domain",
"meta_description": "Example meta description",
"h1_count": 1,
"used_playwright": false,
"screenshots": [],
"checks": [
{ "id": "title", "title": "Sayfa başlığı", "status": "ok", "message": "Başlık mevcut." }
],
"headings": [
{ "level": 1, "text": "Example Heading", "is_valid": true }
],
"keyword_checks": [
{ "keyword": "seo", "in_title": true, "in_meta": false, "in_h1": true, "count": 3, "density_pct": 0.24 }
],
"schema_types": ["WebPage"],
"server": { "ttfb_sec": 0.18, "total_sec": 0.42 },
"attribution": {
"text": "Powered by Spindora",
"url": "https://www.spindorai.com",
"required": true
}
}Attribution (Zorunlu)
Entegre ettiğiniz arayüzde analiz sonuçlarının yakınında görünür ve tıklanabilir attribution göstermelisiniz:
<a href="https://www.spindorai.com" target="_blank" rel="noopener">Powered by Spindora</a>Kod Örnekleri
curl -X POST "https://www.spindorai.com/api/public-seo-analizi/analyze" \
-H "Content-Type: application/json" \
-H "X-Spindora-Key: sp_seo_YOUR_KEY_HERE" \
-d '{
"url": "https://example.com",
"keywords": ["seo", "analiz"],
"device": "desktop",
"locale": "tr"
}'curl "https://www.spindorai.com/api/public-seo-analizi/result/TASK_ID_HERE" \
-H "X-Spindora-Key: sp_seo_YOUR_KEY_HERE"const API = 'https://www.spindorai.com/api/public-seo-analizi';
const KEY = 'sp_seo_YOUR_KEY_HERE';
async function analyzeUrl(url) {
const start = await fetch(`${API}/analyze`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Spindora-Key': KEY,
},
body: JSON.stringify({
url,
keywords: [],
device: 'desktop',
locale: 'tr',
}),
});
const { task_id } = await start.json();
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 2000));
const res = await fetch(`${API}/result/${task_id}`, {
headers: { 'X-Spindora-Key': KEY },
});
if (res.status === 202) continue;
if (!res.ok) throw new Error(await res.text());
return res.json();
}
throw new Error('Timeout');
}// Node.js 18+ (native fetch)
const API = 'https://www.spindorai.com/api/public-seo-analizi';
const KEY = 'sp_seo_YOUR_KEY_HERE';
async function analyzeUrl(url) {
const startRes = await fetch(`${API}/analyze`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Spindora-Key': KEY,
},
body: JSON.stringify({
url,
keywords: [],
device: 'desktop',
locale: 'tr',
}),
});
const { task_id } = await startRes.json();
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 2000));
const pollRes = await fetch(`${API}/result/${task_id}`, {
headers: { 'X-Spindora-Key': KEY },
});
if (pollRes.status === 202) continue;
if (!pollRes.ok) throw new Error(await pollRes.text());
return pollRes.json();
}
throw new Error('Timeout');
}import time
import requests
API = "https://www.spindorai.com/api/public-seo-analizi"
KEY = "sp_seo_YOUR_KEY_HERE"
HEADERS = {"X-Spindora-Key": KEY}
def analyze(url: str) -> dict:
r = requests.post(
f"{API}/analyze",
headers={**HEADERS, "Content-Type": "application/json"},
json={"url": url, "keywords": [], "device": "desktop", "locale": "tr"},
timeout=30,
)
r.raise_for_status()
task_id = r.json()["task_id"]
for _ in range(60):
time.sleep(2)
poll = requests.get(f"{API}/result/{task_id}", headers=HEADERS, timeout=30)
if poll.status_code == 202:
continue
poll.raise_for_status()
return poll.json()
raise TimeoutError("Analysis timed out")<?php
$api = 'https://www.spindorai.com/api/public-seo-analizi';
$key = 'sp_seo_YOUR_KEY_HERE';
function analyze(string $url): array {
global $api, $key;
$ch = curl_init("$api/analyze");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"X-Spindora-Key: $key",
],
CURLOPT_POSTFIELDS => json_encode([
'url' => $url,
'keywords' => [],
'device' => 'desktop',
'locale' => 'tr',
]),
]);
$body = curl_exec($ch);
curl_close($ch);
$taskId = json_decode($body, true)['task_id'];
for ($i = 0; $i < 60; $i++) {
sleep(2);
$ch = curl_init("$api/result/$taskId");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["X-Spindora-Key: $key"],
]);
$poll = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code === 202) continue;
if ($code !== 200) throw new RuntimeException($poll);
return json_decode($poll, true);
}
throw new RuntimeException('Timeout');
}import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class SpindoraSeoClient {
private static final String API = "https://www.spindorai.com/api/public-seo-analizi";
private static final String KEY = "sp_seo_YOUR_KEY_HERE";
private static final HttpClient CLIENT = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
public static String analyze(String url) throws Exception {
String payload = "{\"url\":\"" + url + "\",\"keywords\":[],\"device\":\"desktop\",\"locale\":\"tr\"}";
HttpRequest start = HttpRequest.newBuilder()
.uri(URI.create(API + "/analyze"))
.header("Content-Type", "application/json")
.header("X-Spindora-Key", KEY)
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
String startJson = CLIENT.send(start, HttpResponse.BodyHandlers.ofString()).body();
int marker = startJson.indexOf("\"task_id\":\"");
String taskId = startJson.substring(marker + 11, startJson.indexOf('\"', marker + 11));
for (int i = 0; i < 60; i++) {
Thread.sleep(2000);
HttpRequest poll = HttpRequest.newBuilder()
.uri(URI.create(API + "/result/" + taskId))
.header("X-Spindora-Key", KEY)
.GET()
.build();
HttpResponse<String> res = CLIENT.send(poll, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() == 202) continue;
if (res.statusCode() != 200) throw new RuntimeException(res.body());
return res.body();
}
throw new RuntimeException("Timeout");
}
}Yanıt Alanları
| Alan | Açıklama |
|---|---|
| seo_score | 0–100 SEO skoru |
| checks[] | Kontrol listesi (id, title, status, message) |
| headings[] | H1–H6 yapısı |
| keyword_checks[] | Anahtar kelime eşleşmeleri |
| word_count | Kelime sayısı |
| title_text, meta_description | Sayfa başlığı ve meta |
| schema_types[] | Bulunan schema türleri |
| server | TTFB, toplam süre |
| attribution | Zorunlu gösterim bilgisi |
Hata Kodları
| HTTP | Anlam | Ne yapmalı |
|---|---|---|
| 401 | Geçersiz veya eksik API anahtarı | X-Spindora-Key header kontrol et |
| 429 | Günlük kota doldu | Yarın tekrar dene veya yeni key |
| 202 | Analiz devam ediyor | 2 sn sonra tekrar poll et |
| 422 | URL erişilemedi / analiz hatası | URL ve erişilebilirlik kontrol et |
| 500 | Sunucu / kuyruk hatası | Kısa süre sonra tekrar dene |
Hata gövdesi genelde { "detail": "..." }
Entegrasyon Kontrol Listesi
- ✓API anahtarı oluşturuldu ve güvenli saklanıyor
- ✓Her istekte X-Spindora-Key header gönderiliyor
- ✓POST /analyze sonrası task_id alınıp poll döngüsü kuruldu
- ✓202 yanıtında bekleniyor, 200 gelince JSON parse ediliyor
- ✓screenshots[] API'de boş — UI'da göstermeye çalışma
- ✓Sonuç ekranında Powered by Spindora linki görünür
- ✓429 için kullanıcıya anlamlı mesaj gösteriliyor
AI / LLM için özet
Bir AI asistanına entegrasyon yazdırırken bu metni veya OpenAPI JSON linkini yapıştırın:
# Spindora SEO Analiz API — Entegrasyon Özeti
Base URL: https://www.spindorai.com/api/public-seo-analizi
Dokümantasyon: https://www.spindorai.com/developers/seo-analizi-api
OpenAPI JSON: https://www.spindorai.com/developers/seo-analizi-api.openapi.json
API Key oluştur: Kayıt ol → giriş yap → sidebar'dan "Seo Analiz Aracı API Key Oluşturma" → https://www.spindorai.com/seo-analizi-api-key (ücretsiz hesap)
## Kimlik doğrulama
Header: X-Spindora-Key: sp_seo_YOUR_KEY
Alternatif: Authorization: Bearer sp_seo_YOUR_KEY
## Akış (asenkron)
1. POST /analyze → body: {"url":"https://example.com","keywords":[],"device":"desktop","locale":"tr"}
2. Yanıttan task_id al
3. GET /result/{task_id} — 2 saniyede bir poll et
4. HTTP 202 = devam ediyor, HTTP 200 = sonuç hazır
## Zorunluluklar
- API key harici entegrasyonlarda zorunlu
- Günlük limit: 30 analiz / API key
- screenshots[] API'de her zaman boş
- UI'da zorunlu attribution: <a href="https://www.spindorai.com">Powered by Spindora</a>
## Hata kodları
401 geçersiz key | 429 kota doldu | 202 bekliyor | 422 analiz hatası | 500 sunucu hatasıOpenAPI: https://www.spindorai.com/developers/seo-analizi-api.openapi.json