GEOpta API

A REST API to measure, fix and prove GEO — pull AI-visibility data into Looker, GA4, HubSpot or your own app, and trigger scans, audits and generation. Pay-as-you-go, no subscription needed: read endpoints are free; metered calls cost credits.

Base · https://geopta.com/v1Bearer authJSON120 req/minOpenAPI spec ↗

Authentication

Create a key under Developer & API and send it as a bearer token. Keys have a scope (read / write) and a mode (live / test). geo_test_ keys run in sandbox mode and never charge credits — perfect for CI.

curl https://geopta.com/v1/clients/Acme/scorecard \
  -H "Authorization: Bearer geo_live_…"

Core concepts

Credits & pricing

Reads are free. Each scan / ask / generate / sandbox / agent-ready costs 1 credit. Variable endpoints (locale-scan, conversation) cost credits proportional to the work (~1 per 3 locales). Buy credits at /billing — they never expire and need no subscription. Check your balance at GET /v1/usage.

Rate limits

120 requests/minute per key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 includes Retry-After.

Idempotency

Send Idempotency-Key: <uuid> on POST /v1/scans — a retry returns the original response instead of charging another credit.

Errors

Non-2xx responses use a consistent envelope:

{
  "error": {
    "code": "insufficient_credits",
    "message": "This run needs 2 credits but you have 1. Top up at /billing.",
    "docs": "https://geopta.com/docs/api"
  }
}

Pagination

List endpoints accept ?limit (max 100) & ?cursor, and return nextCursor (null at the end) plus total.

Webhooks & signatures

Subscribe a URL to scan, alert and remediation events. Non-Slack deliveries are signed with X-GEOpta-Signature: sha256=… — an HMAC of the raw body using your webhook secret (rotate it in Developer & API). Verify like so:

const sig = req.headers["x-geopta-signature"];           // "sha256=…"
const mac = "sha256=" + crypto.createHmac("sha256", SECRET)
  .update(rawBody).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(mac))) reject();

Example delivery

{
  "source": "geopta",
  "event": "scan",
  "at": "2026-06-21T09:12:00Z",
  "brand": "Acme",
  "score": 64,
  "delta": 2,
  "mentionRate": "5/6"
}

MCP server (for AI agents)

Let Claude, Cursor or any MCP client query your GEO data as a tool. Point it at the GEOpta MCP server with one of your keys:

GEOPTA_API_KEY=geo_live_… node src/mcp.js
# tools: list_clients · get_visibility · check_visibility
#        audit_product · get_roi · run_scan · get_surfaces

Clients

GET/clients

List your tracked brands with their latest visibility score. Paginated via ?limit & ?cursor.

Request
curl https://geopta.com/v1/clients?limit=2 \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "clients": [
    {
      "brand": "Acme",
      "niche": "CRM software",
      "website": "acme.com",
      "visibilityScore": 62,
      "lastScan": "2026-06-21T09:12:00Z"
    }
  ],
  "nextCursor": null,
  "total": 1
}
POST/clients

Create a brand to track. Write key required.

Request
curl -X POST https://geopta.com/v1/clients \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brand":"Acme","website":"acme.com",
      "prompts":["best CRM for startups"],
      "competitors":["Salesforce"]}'
Response
{
  "brand": "Acme",
  "type": "app",
  "website": "acme.com",
  "prompts": [
    "best CRM for startups"
  ],
  "competitors": [
    "Salesforce"
  ]
}
GET/clients/{brand}/scorecard

The latest full scorecard — score, mention/citation rate, top competitors and cited sources.

Request
curl https://geopta.com/v1/clients/Acme/scorecard \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "scannedAt": "2026-06-21T09:12:00Z",
  "visibilityScore": 62,
  "mentionRate": "4/6",
  "citationRate": "1/6",
  "topCompetitors": [
    {
      "name": "Salesforce",
      "count": 5
    }
  ],
  "topCitedSources": [
    {
      "name": "g2.com",
      "count": 3
    }
  ]
}
GET/clients/{brand}/roi

Full-funnel ROI: AI referral → signup → revenue → LTV, per engine.

Request
curl https://geopta.com/v1/clients/Acme/roi \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "totals": {
    "visits": 1240,
    "conversions": 38,
    "revenue30": 182000,
    "ltv": 2184000,
    "roi": 4.2
  },
  "headline": "ChatGPT drove ₹1,82,000 this month from 22 signups — 60% of your AI revenue."
}

Scans (async)

POST/scans

Start a scan job (1 credit). Pass an Idempotency-Key so a retry never double-charges.

Request
curl -X POST https://geopta.com/v1/scans \
  -H "Authorization: Bearer geo_live_…" \
  -H "Idempotency-Key: 9f8b2c…" \
  -d '{"brand":"Acme"}'
Response
{
  "jobId": "job_3a9f…",
  "status": "queued",
  "poll": "https://geopta.com/v1/scans/job_3a9f…",
  "mode": "live"
}
GET/scans/{jobId}

Poll a job until status is done (or error).

Request
curl https://geopta.com/v1/scans/job_3a9f… \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "id": "job_3a9f…",
  "brand": "Acme",
  "status": "done",
  "result": {
    "brand": "Acme",
    "visibilityScore": 64,
    "mentionRate": "5/6",
    "prev": 62
  }
}
POST/scans/bulk

Kick off scans for many brands at once (one job each).

Request
curl -X POST https://geopta.com/v1/scans/bulk \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brands":["Acme","Beta","Gamma"]}'
Response
{
  "jobs": [
    {
      "brand": "Acme",
      "jobId": "job_a1…"
    },
    {
      "brand": "Beta",
      "jobId": "job_b2…"
    }
  ]
}

Ad-hoc insights

POST/ask

Run any prompt across the engines without saving a client (1 credit).

Request
curl -X POST https://geopta.com/v1/ask \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brand":"Acme","prompt":"best CRM for startups",
      "competitors":["Salesforce"]}'
Response
{
  "brand": "Acme",
  "prompt": "best CRM for startups",
  "engines": [
    {
      "engine": "gemini",
      "mentioned": true,
      "cited": false,
      "position": 18
    },
    {
      "engine": "claude",
      "mentioned": false
    }
  ],
  "mentionRate": "1/2",
  "mentioned": true
}
POST/agent-ready

Audit a product URL for AI-shopping-agent readiness (1 credit).

Request
curl -X POST https://geopta.com/v1/agent-ready \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"url":"https://acme.com/p/pro","brand":"Acme"}'
Response
{
  "url": "https://acme.com/p/pro",
  "score": 78,
  "verdict": "ready",
  "product": {
    "price": "49.00",
    "currency": "USD",
    "availability": "InStock"
  },
  "access": {
    "accessScore": 88
  }
}
POST/sandbox

Predict a draft page's citation-likelihood lift before you publish (1 credit).

Request
curl -X POST https://geopta.com/v1/sandbox \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brand":"Acme","content":"# Best CRM for startups\nAcme is…"}'
Response
{
  "geoScore": 71,
  "grade": "Moderate",
  "predicted": {
    "currentScore": 62,
    "projectedScore": 71,
    "liftPoints": 9
  }
}

Generate & localize

POST/generate

Paste-ready on-site assets: JSON-LD schema, llms.txt and FAQ (1 credit).

Request
curl -X POST https://geopta.com/v1/generate \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brand":"Acme"}'
Response
{
  "aiUsed": true,
  "schemaJsonLd": "{ \"@context\": \"https://schema.org\", … }",
  "llmsTxt": "# Acme\\n…",
  "faqs": [
    {
      "q": "What is Acme?",
      "a": "Acme is a CRM…"
    }
  ]
}
POST/locale-scan

Async multi-language visibility scan. Credits scale with locales (~1 per 3).

Request
curl -X POST https://geopta.com/v1/locale-scan \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"brand":"Acme","locales":["en-US","hi-IN","ta-IN"]}'
Response
{
  "jobId": "job_lc…",
  "status": "queued",
  "creditsCharged": 1,
  "poll": "https://geopta.com/v1/scans/job_lc…"
}

Webhooks

GET/webhooks

List your webhook subscriptions.

Request
curl https://geopta.com/v1/webhooks \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "webhooks": [
    {
      "id": "wh_1",
      "url": "https://api.acme.com/geopta",
      "events": [
        "scan",
        "alert"
      ],
      "format": "json"
    }
  ]
}
POST/webhooks

Subscribe a URL to scan / alert / remediation events.

Request
curl -X POST https://geopta.com/v1/webhooks \
  -H "Authorization: Bearer geo_live_…" \
  -d '{"url":"https://api.acme.com/geopta",
      "events":["scan","alert"]}'
Response
{
  "webhooks": [
    {
      "id": "wh_2",
      "url": "https://api.acme.com/geopta",
      "events": [
        "scan",
        "alert"
      ],
      "format": "json"
    }
  ]
}

Account & meta

GET/usage

Your plan, credit balance and remaining scans.

Request
curl https://geopta.com/v1/usage \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "plan": "free",
  "mode": "live",
  "scope": "write",
  "monthlyScans": 0,
  "credits": 23,
  "remaining": 23,
  "resetsAt": "2026-06-30T18:30:00Z"
}
GET/surfaces

The map of AI surfaces GEOpta measures.

Request
curl https://geopta.com/v1/surfaces \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "counts": {
    "live": 4,
    "proxy": 2,
    "roadmap": 7
  },
  "regions": [
    "Global",
    "India"
  ]
}
GET/export

Delta export of snapshots for a warehouse sync (?since=ISO8601).

Request
curl "https://geopta.com/v1/export?since=2026-06-01" \
  -H "Authorization: Bearer geo_live_…"
Response
{
  "since": "2026-06-01",
  "count": 128,
  "snapshots": [
    {
      "brand": "Acme",
      "scannedAt": "2026-06-21T09:12:00Z",
      "visibilityScore": 62
    }
  ]
}