Dokumentation

Available Endpoints

This page lists all endpoints that support API key authentication. Most endpoints use your property API key; the AIVPS endpoints below use your organization API key. For interactive documentation and testing, visit the API Reference.

The API Reference shows all endpoints, but only the ones listed below support external API key access. Other endpoints are for internal application use only.

AI Placement Value Score (AIVPS)

Programmatically score one or more publisher domains against the AI Placement Value Score (AIVPS) layers — organic authority, AI citation accessibility, and AI training influence. Use this to rank placement opportunities, monitor AI-era authority of partner and competitor domains, and feed SEO/PR workflows that already track traditional authority metrics.

These endpoints use an organization-level API key, not your property API key. The two are not interchangeable. Generate a key under Organization Settings → API Key. A single organization key authorizes AIVPS scoring across every domain your organization queries.

Score Publishers

Compute the full AIVPS for one or more publisher domains. If the domain is unknown to Spyglasses, a publisher record is auto-created and enriched asynchronously in the background — the first call may return "confidence": "estimated" while enrichment finishes.

POST /api/v1/ai-impact

Headers:

  • x-api-key: Your organization's AIVPS API key (required)
  • Content-Type: application/json

Body (primary use case — score a batch against a brand):

{
  "domains": ["wirecutter.com", "nytimes.com", "techcrunch.com"],
  "brandContext": {
    "propertyId": "YOUR_PROPERTY_ID"
  }
}
  • domain (string) or domains (array, 1–25) — supply exactly one. Domains are normalized (protocol/www/trailing slash stripped).
  • brandContext.propertyId (optional) — must reference a Property owned by the authenticated organization. Enables category-relevance scoring and AI training influence uplift. Omit if you don't have brand context.
  • baseline (optional) — enables Bring-Your-Own-Baseline mode. See below.

Response:

{
  "success": true,
  "results": [
    {
      "domain": "wirecutter.com",
      "publisher": {
        "id": "cm...",
        "domain": "wirecutter.com",
        "name": "Wirecutter",
        "logoUrl": "https://...",
        "aiPolicyStatus": "green",
        "organicMetricsFetchedAt": "2026-04-01T12:00:00.000Z"
      },
      "aipvs": {
        "domain": "wirecutter.com",
        "aipvs": 78,
        "tier": 1,
        "tierLabel": "Premium",
        "aiImpactMultiplier": 0.82,
        "confidence": "exact",
        "confidenceReason": "...",
        "layers": { "oab": { "..." }, "aca": { "..." }, "ati": { "..." } },
        "weightVersion": "2026-Q1",
        "scoredAt": "2026-04-12T18:30:00.000Z"
      },
      "needsEnrichment": false,
      "created": false
    }
  ],
  "errors": []
}

If any individual domain fails (for example, a missing baseline value in BYOB mode), that domain appears in errors[] and the rest of the batch still succeeds.


Score Publishers with Bring-Your-Own-Baseline (BYOB)

If your team already tracks organic authority with Ahrefs DR, Moz DA, SEMrush AS, Majestic TF, or a custom score, you can supply that baseline and have Spyglasses apply only the AI layers on top. The response's aipvsByob.compositeScore is computed as normalizedBaseline × aiImpactMultiplier.

POST /api/v1/ai-impact

Body:

{
  "domains": ["wirecutter.com", "techcrunch.com"],
  "brandContext": { "propertyId": "YOUR_PROPERTY_ID" },
  "baseline": {
    "source": "ahrefs_dr",
    "values": {
      "wirecutter.com": 88,
      "techcrunch.com": 91
    }
  }
}
  • baseline.source — one of ahrefs_dr, moz_da, semrush_as, majestic_tf, dataforseo, custom.
  • baseline.values — map of domain → baseline value. Must contain an entry for every domain you pass in.
  • baseline.customMin / customMax — required when source is custom; values are linearly rescaled to 0–100.

Response (adds an aipvsByob block per result; standard aipvs is still included for reference):

{
  "success": true,
  "results": [
    {
      "domain": "wirecutter.com",
      "publisher": { "..." },
      "aipvs": { "..." },
      "aipvsByob": {
        "baselineSource": "ahrefs_dr",
        "externalBaseline": 88,
        "compositeScore": 72,
        "tier": 2,
        "tierLabel": "Strong",
        "aiImpactMultiplier": 0.82,
        "layers": { "aca": { "..." }, "ati": { "..." } }
      },
      "needsEnrichment": false,
      "created": false
    }
  ],
  "errors": []
}

Get AI Impact Multiplier

Returns just the raw AI impact multiplier (0.40–1.00) plus the ACA and ATI layers for one or more domains. Use this when you want to combine Spyglasses' AI layers with a baseline you compute yourself at call time — the most portable form of the AIVPS signal.

POST /api/v1/ai-impact/multiplier

Headers:

  • x-api-key: Your organization's AIVPS API key (required)
  • Content-Type: application/json

Body:

{
  "domains": ["wirecutter.com", "techcrunch.com"],
  "brandContext": { "propertyId": "YOUR_PROPERTY_ID" }
}

Response:

{
  "success": true,
  "results": [
    {
      "domain": "wirecutter.com",
      "aiImpactMultiplier": 0.82,
      "layers": {
        "aca": { "composite": 0.91, "platforms": { "..." } },
        "ati": { "composite": 0.74, "dti": 0.8, "uplift": 1.1, "trainingAccessComposite": 0.84, "platforms": { "..." } }
      },
      "confidence": "exact",
      "needsEnrichment": false
    }
  ],
  "errors": []
}

AI Placement Quality Score (PQS)

Programmatically score placements against the AI Placement Quality Score factors — document position, chunk containment, placement type, editorial control, link attribute, and sentiment multiplier. When a publisher domain is supplied, the response also includes the publisher's AIPVS and a combined Total Placement Value (AIPVS × PQS / 100).

The PQS API supports both scoring modes:

  • Prospective (synchronous) — score a hypothetical placement from user-supplied inputs. Returns the full score in the POST response.
  • Retrospective (async, polling) — score an existing placement at a live URL. The POST creates a placement and enqueues the background job; the client polls a GET endpoint for the result.

All PQS endpoints use an organization-level API key, the same key used for the AIVPS endpoints above. Generate one under Organization Settings → API Key.

Score a Prospective Placement

Compute the PQS for a hypothetical placement given its scoring inputs. Use this to rank placement offers, run "what-if" scenarios before negotiating, or integrate PQS into your own media planning tools.

POST /api/v1/ai-impact/placement

Headers:

  • x-api-key: Your organization's API key (required)
  • Content-Type: application/json

Body:

{
  "placementType": "roundup_top_third",
  "editorialControl": "collaborative",
  "linkAttribute": "dofollow",
  "assumedPosition": 0.12,
  "publisherDomain": "wirecutter.com",
  "brandContext": {
    "propertyId": "YOUR_PROPERTY_ID"
  }
}
  • placementType (required) — one of dedicated_article, roundup_top, roundup_top_third, roundup_middle_third, roundup_bottom_third, passing_mention, sidebar_widget_biobox, quote_only
  • editorialControl (required) — one of full_authorship, collaborative, quoted, mentioned, unpredictable
  • linkAttribute (required) — one of dofollow, nofollow, sponsored, ugc, no_link
  • assumedPosition (optional, default 0.15) — the fraction of the document (0.0–1.0) where you expect the brand mention to land. 0.05 = first 10%, 0.5 = middle, 0.95 = footer.
  • publisherDomain (optional) — when supplied, the publisher's AIPVS is computed and combined with the PQS for a Total Placement Value.
  • brandContext.propertyId (optional) — must reference a Property owned by the authenticated organization. Narrows AIPVS category relevance and training influence uplift.

Response:

{
  "success": true,
  "pqs": {
    "pqsScore": 79,
    "rawWeightedScore": 79,
    "subScores": {
      "position": 0.85,
      "chunk": 0.7,
      "type": 0.75,
      "editorial": 0.85,
      "link": 1.0
    },
    "sentimentMultiplier": 1.0,
    "sentimentCategory": "neutral",
    "effectiveWeights": {
      "position": 0.3,
      "chunk": 0.2,
      "type": 0.2,
      "editorial": 0.15,
      "link": 0.15
    },
    "defaultWeights": {
      "position": 0.3,
      "chunk": 0.2,
      "type": 0.2,
      "editorial": 0.15,
      "link": 0.15
    },
    "inputs": {
      "placementType": "roundup_top_third",
      "editorialControl": "collaborative",
      "linkAttribute": "dofollow",
      "assumedPosition": 0.12
    }
  },
  "aipvs": {
    "publisher": {
      "id": "cm...",
      "domain": "wirecutter.com",
      "name": "Wirecutter",
      "logoUrl": "https://...",
      "aiPolicyStatus": "green",
      "organicMetricsFetchedAt": "2026-04-01T12:00:00.000Z"
    },
    "aipvs": {
      "domain": "wirecutter.com",
      "aipvs": 78,
      "tier": 1,
      "tierLabel": "Premium",
      "aiImpactMultiplier": 0.82,
      "confidence": "exact",
      "layers": { "oab": { "..." }, "aca": { "..." }, "ati": { "..." } }
    },
    "needsEnrichment": false
  },
  "totalPlacementValue": 62
}

Notes:

  • pqs.subScores.chunk is always 0.7 for prospective placements. Actual chunk containment can only be computed from real content, so the API treats prospective placements as "partial" containment by default. Retrospective scoring (via the web UI) computes the real value.
  • pqs.sentimentMultiplier is always 1.0 for prospective placements. Sentiment analysis requires real content around the mention.
  • aipvs and totalPlacementValue are null when publisherDomain is omitted or the AIPVS lookup fails.
  • pqs.effectiveWeights matches defaultWeights in prospective mode. Retrospective mode (web UI only) redistributes the editorial weight proportionally across the other four signals.

Example — run a lift preview: Fire several requests with the same publisher and editorial control but different placement positions / link attributes to quantify how much better terms would be worth. This is exactly what the "What if you negotiated better terms?" panel in the web UI does.


Score a Retrospective Placement (asynchronous)

Score an existing placement at a live URL. Spyglasses fetches the page, locates the brand mention (using the property's name and aliases), auto-detects the link attribute, classifies placement type and sentiment with an AI model, and computes the PQS. The pipeline typically takes 15–30 seconds and runs as a background job, so this endpoint returns a placement ID immediately — you poll for the result.

POST /api/v1/ai-impact/placement/retrospective

Headers:

  • x-api-key: Your organization's API key (required)
  • Content-Type: application/json

Body:

{
  "url": "https://www.prnewswire.com/news-releases/example-article",
  "propertyId": "YOUR_PROPERTY_ID"
}
  • url (required) — the live URL to score. Must be publicly accessible.
  • propertyId (required) — the Property whose brand name and aliases should be used to locate the mention in the content. Must belong to the authenticated organization.
  • title (optional) — a human-readable label for the placement. Auto-extracted from the page's <title> / og:title / h1 if omitted.
  • placementType / editorialControl / linkAttribute (optional) — all three are auto-detected from the page during scoring. Only supply them if you want to override the auto-detection.

Response (HTTP 202):

{
  "success": true,
  "id": "cm_placement_abc123",
  "status": "pending",
  "mode": "retrospective",
  "url": "https://www.prnewswire.com/news-releases/example-article",
  "createdAt": "2026-04-15T14:30:00.000Z",
  "pollUrl": "/api/v1/ai-impact/placement/cm_placement_abc123",
  "pollIntervalSeconds": 3,
  "estimatedCompletionSeconds": 30
}

The returned id is the placement's unique identifier. Use it with the polling endpoint below.


Poll a Placement's Status and Result

Fetch the current state of a placement created via the retrospective endpoint (or any placement owned by the authenticated organization). Poll at roughly 3-second intervals until status is completed or failed.

GET /api/v1/ai-impact/placement/:id

Headers:

  • x-api-key: Your organization's API key (required)

Response while scoring is still in progress (HTTP 200):

{
  "success": true,
  "id": "cm_placement_abc123",
  "status": "running",
  "mode": "retrospective",
  "url": "https://www.prnewswire.com/news-releases/example-article",
  "createdAt": "2026-04-15T14:30:00.000Z",
  "startedAt": "2026-04-15T14:30:01.000Z",
  "pollUrl": "/api/v1/ai-impact/placement/cm_placement_abc123",
  "pollIntervalSeconds": 3
}
  • status is either pending (queued, not yet running) or running (actively being scored).
  • Keep polling until status changes to completed or failed.

Response when scoring has completed (HTTP 200):

{
  "success": true,
  "id": "cm_placement_abc123",
  "status": "completed",
  "mode": "retrospective",
  "url": "https://www.prnewswire.com/news-releases/example-article",
  "title": "Example Company partners with Acme for industrial decarbonization",
  "createdAt": "2026-04-15T14:30:00.000Z",
  "completedAt": "2026-04-15T14:30:24.000Z",
  "pqs": {
    "pqsScore": 72,
    "rawWeightedScore": 72,
    "subScores": {
      "position": 0.85,
      "chunk": 1.0,
      "type": 0.75,
      "editorial": 0.5,
      "link": 0.6
    },
    "sentimentMultiplier": 1.0,
    "sentimentCategory": "neutral",
    "sentimentPolarity": 0.52,
    "effectiveWeights": {
      "position": 0.353,
      "chunk": 0.235,
      "type": 0.235,
      "editorial": 0,
      "link": 0.176
    },
    "defaultWeights": { "position": 0.3, "chunk": 0.2, "type": 0.2, "editorial": 0.15, "link": 0.15 },
    "inputs": {
      "placementType": "roundup_top_third",
      "editorialControl": "mentioned",
      "linkAttribute": "nofollow",
      "positionPercent": 0.18
    },
    "brandMention": {
      "matchedAlias": "Example Company",
      "tokenIndex": 287,
      "totalTokens": 1620
    },
    "keyMessagePullThrough": {
      "matches": [
        {
          "keyMessageId": "cm_km_001",
          "message": "Zero-carbon industrial heat",
          "sentenceText": "Example Company provides zero-carbon industrial heat and power...",
          "sentenceCharStart": 1240,
          "sentenceCharEnd": 1380,
          "score": 0.51,
          "matched": true
        }
      ],
      "threshold": 0.4
    }
  },
  "aipvs": {
    "publisher": { "id": "cm_pub_xyz", "domain": "prnewswire.com", "name": "PR Newswire", "..." },
    "aipvs": { "domain": "prnewswire.com", "aipvs": 68, "tier": 2, "tierLabel": "Strong", "..." },
    "needsEnrichment": false
  },
  "totalPlacementValue": 49
}

Notes:

  • In retrospective mode, the editorial weight is redistributed proportionally across the other four signals (effectiveWeights.editorial = 0) because the editorial decision has already been made. The defaultWeights field shows the original distribution for reference.
  • pqs.inputs reflects the auto-detected values after scoring, not necessarily what you passed in the create request. If the scorer detected a different link attribute or placement type, those take precedence.
  • pqs.brandMention shows which alias matched and where it was located in the tokenized content.
  • keyMessagePullThrough.matches is always one entry per configured key message (even below-threshold "closest match" entries); the matched flag indicates whether each crossed the threshold.
  • totalPlacementValue is null when the publisher couldn't be looked up or hasn't been enriched yet.

Response when scoring has failed (HTTP 200):

{
  "success": false,
  "id": "cm_placement_abc123",
  "status": "failed",
  "errorMessage": "No brand mention found in content. Check the URL or add brand aliases to the Property.",
  "mode": "retrospective",
  "url": "https://www.prnewswire.com/news-releases/example-article",
  "createdAt": "2026-04-15T14:30:00.000Z",
  "completedAt": "2026-04-15T14:30:12.000Z"
}

Common failure modes:

  • "No brand mention found in content" — the scorer couldn't locate any occurrence of the Property's name or aliases in the page. Check the URL is correct and add the exact form of the brand name used in the article to the Property's aliases.
  • "The URL returned 404 — check that it's correct and publicly accessible." — the page no longer exists or isn't publicly available.
  • "The URL returned 403 — the site is blocking our crawler." — the site is blocking the Spyglasses fetcher via WAF or bot protection. Try a different page on the same site.
  • "Could not extract readable content from the page." — the page is JavaScript-rendered, paywalled, or has an unusual layout that prevents content extraction.

Polling example (JavaScript):

async function scoreRetrospectivePlacement(url, propertyId, apiKey) {
  // 1. Create the placement and get back an ID
  const createRes = await fetch("/api/v1/ai-impact/placement/retrospective", {
    method: "POST",
    headers: { "Content-Type": "application/json", "x-api-key": apiKey },
    body: JSON.stringify({ url, propertyId }),
  });
  const { id, pollUrl, pollIntervalSeconds } = await createRes.json();
 
  // 2. Poll until the placement is completed or failed
  while (true) {
    await new Promise((r) => setTimeout(r, pollIntervalSeconds * 1000));
    const poll = await fetch(pollUrl, { headers: { "x-api-key": apiKey } });
    const result = await poll.json();
    if (result.status === "completed") return result;
    if (result.status === "failed") throw new Error(result.errorMessage);
    // Otherwise keep polling (status === "pending" or "running")
  }
}

Property Information

Get Property Details

Retrieve information about your property using your API key.

GET /api/me

Headers:

  • x-api-key: Your API key (required)

Response:

{
  "propertyId": "cm9ovvnnc0001wjubh0en0cpe",
  "domain": "example.com",
  "companyName": "Example Company",
  "apiKey": "sg_XXX...",
  "verified": true,
  "verifiedAt": "2025-01-01T00:00:00.000Z",
  "blockAiModelTrainers": false,
  "customBlocks": [],
  "customAllows": []
}

AI Visibility Rankings

Get AI Visibility Rankings

Retrieve prioritized grounding search opportunities from your most recent AI report.

GET /api/ai-rankings/:propertyId

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • propertyId: Your property ID (from /api/me)

Historical Metrics

Get Brand Consistency History

Retrieve brand consistency score trends over time.

GET /api/properties/:id/historical-metrics/brand-consistency

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • id: Your property ID

Get Discovery Metrics History

Retrieve discovery query performance trends over time.

GET /api/properties/:id/historical-metrics/discovery

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • id: Your property ID

Get Grounding Search Metrics History

Retrieve grounding search ranking trends over time.

GET /api/properties/:id/historical-metrics/grounding-searches

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • id: Your property ID

Query Parameters:

  • onlyGaps: Set to "true" to filter to gap opportunities only

Get Competitor Share of Voice

Retrieve share of voice data for competitors from your most recent AI report.

GET /api/properties/:id/competitor-sov

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • id: Your property ID

Get AI Visibility Rankings (Alternative)

Alternative endpoint for AI visibility rankings data.

GET /api/properties/:id/ai-visibility-rankings

Headers:

  • x-api-key: Your API key (required)

Parameters:

  • id: Your property ID

AI Traffic Analytics

Retrieve AI traffic timeline data with comparison to previous period.

POST /api/analytics/ai/timeline-with-trends

Headers:

  • x-api-key: Your API key (required)
  • Content-Type: application/json

Body:

{
  "propertyApiKey": "sg_YOUR_API_KEY",
  "timeRange": {
    "start": "2025-01-01T00:00:00Z",
    "end": "2025-01-31T23:59:59Z"
  },
  "granularity": "day"
}

Get AI Conversion Metrics

Retrieve AI conversion metrics showing bot visits vs human visits.

POST /api/analytics/ai/conversion-metrics

Headers:

  • x-api-key: Your API key (required)
  • Content-Type: application/json

Body:

{
  "propertyApiKey": "sg_YOUR_API_KEY",
  "timeRange": {
    "start": "2025-01-01T00:00:00Z",
    "end": "2025-01-31T23:59:59Z"
  },
  "sessionWindowMinutes": 5
}

Get AI Traffic Summary

Retrieve AI traffic summary with breakdowns by category and referrer.

POST /api/analytics/ai/traffic-summary

Get AI Traffic Timeline

Retrieve AI traffic timeline data for charts.

POST /api/analytics/ai/timeline

Get AI Traffic Timeline by Intent

Retrieve AI traffic timeline segmented by page intent.

POST /api/analytics/ai/timeline-by-intent

Get AI Overview Visits

Retrieve visits from Google AI Overviews, Featured Snippets, and People Also Ask.

POST /api/analytics/ai/ai-overview-visits

Get Bot Types

Retrieve list of AI visitor bot types for filtering.

GET /api/analytics/ai/bot-types

Agent Analytics

Get Agent Data by Category

Retrieve analytics data for agents grouped by category.

POST /api/analytics/agent/category

Headers:

  • x-api-key: Your API key (required)
  • Content-Type: application/json

Body:

{
  "propertyId": "YOUR_PROPERTY_ID",
  "timeRange": {
    "start": "2025-01-01T00:00:00Z",
    "end": "2025-01-31T23:59:59Z"
  }
}

Get Agent Data by Subcategory

Retrieve analytics data for agents grouped by subcategory.

POST /api/analytics/agent/subcategory

Get Agent Data by Bot Type

Retrieve analytics data for agents grouped by bot type.

POST /api/analytics/agent/bot-type

Get Agent Data by Location

Retrieve analytics data for agents grouped by location.

POST /api/analytics/agent/location

Get Agent Data by Pages

Retrieve analytics data for agents grouped by page path.

POST /api/analytics/agent/pages

Get Live Agent Data

Retrieve real-time agent data for a property.

GET /api/analytics/agent/live/:propertyId

Get Blocked Requests Statistics

Retrieve statistics about blocked vs allowed requests.

POST /api/analytics/agent/blocked-stats

Recrawl Analytics

Get Site Recrawl Summary

Retrieve site-wide recrawl frequency statistics.

POST /api/analytics/recrawl/summary

Headers:

  • x-api-key: Your API key (required)
  • Content-Type: application/json

Body:

{
  "propertyId": "YOUR_PROPERTY_ID",
  "timeRange": {
    "start": "2025-01-01T00:00:00Z",
    "end": "2025-01-31T23:59:59Z"
  }
}

Get Page Recrawl Frequency

Retrieve recrawl frequency statistics for each page.

POST /api/analytics/recrawl/pages

Get Bot Recrawl Frequency

Retrieve recrawl frequency statistics for each crawler bot.

POST /api/analytics/recrawl/bots

Get Bot Page Recrawl Frequency

Retrieve recrawl frequency for pages crawled by a specific bot.

POST /api/analytics/recrawl/bots/:botTypeId/pages

Internal-Only Endpoints

The API Reference shows additional endpoints that are for internal application use only. These endpoints use session-based authentication and are not supported for external API access.

If you need access to data not available through the endpoints listed above, please contact us to discuss your requirements.