Authentication

Generate an API key in your profile (Settings → API Keys), then pass it as the X-API-Key header on every request.

curl -H "X-API-Key: YOUR_API_KEY" \
  https://serp.tsoden.ai/api/v1/clients
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://serp.tsoden.ai"

r = requests.get(f"{BASE}/api/v1/clients",
                 headers={"X-API-Key": API_KEY})
r.raise_for_status()
print(r.json())
const API_KEY = "YOUR_API_KEY";
const BASE = "https://serp.tsoden.ai";

const res = await fetch(`${BASE}/api/v1/clients`, {
  headers: { "X-API-Key": API_KEY }
});
const data = await res.json();
console.log(data);

GETList clients

GET /api/v1/clients — returns all clients accessible to your API key.

curl -H "X-API-Key: $KEY" https://serp.tsoden.ai/api/v1/clients

# Response
{
  "clients": [
    {"id": 1, "name": "Acme Corp", "url": "https://acme.com"},
    {"id": 2, "name": "Foo Ltd",   "url": "https://foo.com"}
  ]
}

POSTTrigger a SERP check

POST /api/v1/clients/<id>/check — queues a SERP check for the keywords of a client. Returns a job_id you can poll.

curl -X POST https://serp.tsoden.ai/api/v1/clients/1/check \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json"

# Response
{"job_id": 42, "status": "queued"}
import requests, time

job = requests.post(
    f"{BASE}/api/v1/clients/1/check",
    headers={"X-API-Key": API_KEY},
).json()
job_id = job["job_id"]

# Poll until done
while True:
    status = requests.get(
        f"{BASE}/api/v1/jobs/{job_id}",
        headers={"X-API-Key": API_KEY},
    ).json()
    if status["status"] in ("completed", "failed"):
        break
    time.sleep(5)
print(status)
const headers = {
  "X-API-Key": API_KEY,
  "Content-Type": "application/json",
};

const job = await fetch(`${BASE}/api/v1/clients/1/check`, {
  method: "POST", headers,
}).then(r => r.json());

console.log("Queued:", job.job_id);

GETFetch keyword positions

GET /api/v1/clients/<id>/keywords — latest position per tracked keyword.

curl -H "X-API-Key: $KEY" \
  https://serp.tsoden.ai/api/v1/clients/1/keywords

# Response (truncated)
{
  "keywords": [
    {"query": "best crm", "position": 4, "lang": "en", "geo": "us", "device": "desktop"},
    {"query": "best crm software", "position": 11, "lang": "en", "geo": "us"}
  ]
}

POSTAdd a keyword

curl -X POST https://serp.tsoden.ai/api/v1/clients/1/keywords \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '[{"query": "new keyword", "lang": "en", "geo": "us", "device": "desktop"}]'

POSTCreate an ASO app profile

POST /api/v1/clients/<id>/aso/apps - adds an App Store or Google Play app profile for ASO tracking.

curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/apps \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "store": "app_store",
    "app_name": "Looks Style Assistant and Shopping",
    "app_identifier": "6760108611",
    "country": "GB",
    "language": "en",
    "category": "Lifestyle",
    "developer": "B-World",
    "app_url": "https://apps.apple.com/gb/app/looks-ai-stylist-and-shoping/id6760108611"
  }'

POSTAdd ASO keywords

POST /api/v1/clients/<id>/aso/keywords - adds App Store or Google Play keywords for ASO visibility tracking.

curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/keywords \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '[{
    "query": "ai stylist",
    "store": "app_store",
    "country": "GB",
    "language": "en"
  }]'

POSTRun ASO refresh actions

These endpoints expose the same latest ASO actions used by Strategy Assistant through REST and MCP: keyword generation, live rankings, listing audit, review fetch, and full refresh.

# Refresh Looks Zone listing metadata from the public App Store page
curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/actions/listing-audit \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"store": "app_store", "max_apps": 1}'

# Fetch public App Store reviews
curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/actions/reviews \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"store": "app_store", "limit": 25, "max_apps": 1}'

# Run live rankings for saved ASO keywords
curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/actions/rankings \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"max_keywords": 25}'

# Full ASO refresh: listing, reviews, rankings
curl -X POST https://serp.tsoden.ai/api/v1/clients/1/aso/actions/full-refresh \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"store": "app_store", "max_apps": 1, "max_keywords": 25, "limit": 25}'

GETRead ASO summary

GET /api/v1/clients/<id>/aso/summary - returns app count, keyword count, visibility, listing audit, reviews, diagnostics, and backlog signals.

curl -H "X-API-Key: $KEY" \
  https://serp.tsoden.ai/api/v1/clients/1/aso/summary

Webhooks

Register a webhook URL under Settings → Webhooks. We POST JSON on these events: job.completed, rank.spike_detected, backlink.gained, backlink.lost, aeo.check_completed.

// Example payload: job.completed
{
  "event": "job.completed",
  "fired_at": 1748000000,
  "data": {
    "job_id": 42,
    "client_id": 1,
    "client_name": "Acme Corp",
    "keywords_checked": 150,
    "duration_seconds": 320
  }
}
Need an endpoint we did not show here? The full interactive spec lives at /public/api/docs.