GeoCites API
Check AI citation visibility programmatically. API scans are BYOK-only so public community traffic cannot drain the shared pool.
Quick Start
Run a BYOK scan with a single request. GeoCites requires your OpenRouter key for API scans so public traffic cannot drain the community pool.
curl -X POST https://geo-cites.com/api/v1/scan \
-H "Authorization: Bearer gc_sk_your_key" \
-H "X-Openrouter-Key: sk-or-v1-..." \
-H "Content-Type: application/json" \
-d '{
"domain": "progevita.com",
"keyword": "longevity clinic",
"location": "Valencia, Spain"
}'Response includes overall score, per-model citation data, geographic radius analysis, and competitor rankings.
X-Openrouter-Key is preferred over the legacy openRouterApiKey body field — most logging and tracing middlewares redact *-key headers by default. The body form still works but the server emits a byok.deprecated_body_key warn on each call.
Authentication
The hosted v1 API is private-access today. Scan and query endpoints require a GeoCites bearer token sent via the Authorization header.
Authorization: Bearer gc_sk_your_keyThe current hosted deployment validates one server-configured key, not per-user keys. Contact contact@geo-cites.com if you need hosted API access. If you self-host GeoCites, set your own GEOCITES_API_KEY and keep it out of client-side code.
For BYOK scans, send your OpenRouter key in the X-Openrouter-Key header (preferred — request headers are redacted by default in most logging/tracing middleware). The legacy openRouterApiKey body field still works but the server emits a byok.deprecated_body_key warn on each call. Either way, send it only from trusted server or agent runtime — GeoCites uses it to execute the scan and does not include it in result payloads.
Endpoints
/api/v1/scanRun a new AI citation scan. Returns full results synchronously (v1 -- async polling coming in v2).
Request Headers
Authorization: Bearer gc_sk_your_key
X-Openrouter-Key: sk-or-v1-...
Content-Type: application/jsonRequest Body
{
"domain": "progevita.com",
"keyword": "longevity clinic",
"location": "Valencia, Spain",
"tier": "byok",
"models": ["openai-latest", "anthropic-opus-latest", "google-gemini-pro-latest"],
"rings": [1, 2],
"questionsPerModel": 3,
"keywordsPerRing": 5,
"queriesPerKeyword": 1
}Response 200
{
"scanId": "a1b2c3d4-...",
"status": "complete",
"cost": "$0.00 to GeoCites (OpenRouter BYOK)",
"result": {
"domain": "progevita.com",
"keyword": "longevity clinic",
"overallScore": 42,
"models": [
{
"model": "openai-latest",
"modelLabel": "OpenAI Latest",
"cited": true,
"score": 72,
"prominence": "secondary"
}
],
"radius": {
"rings": [...],
"topCompetitors": [...]
}
}
}/api/v1/scan/:idRetrieve a previously completed scan by ID. Production results are served from Cloudflare KV.
Response 200
{
"scanId": "a1b2c3d4-...",
"status": "complete",
"result": { ... }
}/api/v1/modelsList BYOK model aliases with resolved OpenRouter model IDs and estimated per-question costs. No authentication required.
Response 200
{
"byok": [
{
"id": "openai-latest",
"name": "OpenAI Latest",
"model": "openai/gpt-5.4",
"costPerQuery": 0.019
},
{
"id": "anthropic-opus-latest",
"name": "Claude Opus Latest",
"model": "~anthropic/claude-opus-latest",
"costPerQuery": 0.03
}
]
}Scan Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | Website domain to check (e.g. progevita.com) |
keyword | string | Yes | Target keyword or topic |
location | string | No | Location for geographic radius (e.g. Valencia, Spain) |
tier | byok | No | API scans are BYOK-only. Defaults to byok |
openRouterApiKey | string | No (header preferred) | Legacy OpenRouter key transport via JSON body — accepted but emits a `byok.deprecated_body_key` warn. Prefer the `X-Openrouter-Key` request header (redacted by default in most logging/tracing middleware). Send only from trusted server or agent runtime; not returned in result payloads. |
models | string[] | No | BYOK model aliases. Defaults to OpenAI, Claude Opus, and Gemini latest |
questionsPerModel | number | No | Core recommendation questions per model (1-10, default: 3) |
keywordsPerRing | number | No | Keywords per selected market (1-50, default: 5) |
queriesPerKeyword | number | No | Prompt variations per keyword (1-10, default: 1) |
Available Models
BYOK Model Aliases (resolved from OpenRouter)
openai-latestanthropic-opus-latestgoogle-gemini-pro-latestperplexity-latestxai-latestzai-latestCode Examples
curl -X POST https://geo-cites.com/api/v1/scan \
-H "Authorization: Bearer gc_sk_your_key" \
-H "X-Openrouter-Key: sk-or-v1-..." \
-H "Content-Type: application/json" \
-d '{
"domain": "progevita.com",
"keyword": "longevity clinic",
"location": "Valencia, Spain",
"tier": "byok",
"models": ["openai-latest", "anthropic-opus-latest", "google-gemini-pro-latest"],
"questionsPerModel": 3
}'Rate Limits
BYOK scans
60 / hour
Per API key
Burst
5 concurrent
Max parallel requests
Pricing
| Plan | Price | Includes |
|---|---|---|
| BYOK scans | $0 to GeoCites | Choose OpenRouter models, up to 15 keywords/ring, OpenRouter bills you directly |
API access is BYOK-only. The web UI still has a constrained free models demo, but API traffic must use the caller's OpenRouter key. Agents can also read /llms.txt for a compact product and endpoint summary.
Error Codes
| Status | Meaning |
|---|---|
200 | Success |
400 | Bad request -- missing or invalid parameters |
401 | Unauthorized -- invalid or missing API key |
404 | Not found -- scan ID does not exist |
429 | Rate limited -- too many requests (planned, not yet enforced) |
500 | Server error -- something went wrong |
Questions? Need hosted API access?
Try GeoCites