API Reference
Integrate SignalSumo's SEO data directly into your own tools, dashboards, and workflows.
Quickstart
Three steps to your first response.
1. Create an API key
On a Pro or Agency plan, generate a key at API Keys and copy it — it's shown only once.
2. Verify the connection
curl -H "Authorization: Bearer ss_live_your_key_here" \
"https://signalsumo.com/api/v1/usage"
A 200 response with your plan and remaining calls means you're connected.
3. Make your first data call
curl -X POST \
-H "Authorization: Bearer ss_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"keyword":"seo audit tool","limit":5}' \
"https://signalsumo.com/api/v1/keyword-research"
Authorization: Bearer header and returns the same JSON envelope — browse the endpoints below for parameters and response fields.
Overview
All API endpoints are served under:
https://signalsumo.com/api/v1/
Requests and responses use JSON. Every response follows the same envelope:
{
"success": true,
"data": { ... },
"meta": { "timestamp": "2026-06-26T10:00:00+00:00" }
}
Errors follow the same shape with success: false and an error object instead of data.
Endpoints fall into two groups, and the difference is what they cost you:
- Research endpoints —
/backlinks,/keyword-research,/site-audit— fetch fresh data from outside SignalSumo. They draw feature quota or credits. See Plans & Billing. - Your-data endpoints — everything under
/rank,/gscand/ai-visibility— read what your account has already collected. They are plain database reads: they cost no credits and no feature quota, and they are never themselves refused for being over the monthly cap.
Authentication
Pass your API key in the Authorization header on every request:
Authorization: Bearer ss_live_your_key_here
Alternatively, you may pass it as a query parameter (not recommended for production):
GET /api/v1/usage?api_key=ss_live_your_key_here
The Authorization: Bearer header is the recommended method. The API also sends permissive CORS headers, so it can be called directly from browser-based tools. Keep secret keys server-side in production.
Plans & Billing
API access is available on the Pro and Agency plans. Two independent meters govern usage — a call is only served when both allow it.
1. Monthly API calls
Every request (including cache hits and errors that reach an endpoint) counts as one API call.
| Plan | Monthly API calls | Resets |
|---|---|---|
| Pro | 20 | 1st of each month |
| Agency | 100 | 1st of each month |
Exceeding this returns HTTP 429 (RATE_LIMITED) with a resets_at field in meta. Check your live limit and usage any time via GET /usage.
2. Per-feature quota & credits
Beyond the call meter, the data endpoints each draw from their own monthly feature quota (the same allowance your logged-in dashboard uses). How each behaves when that quota runs out:
| Endpoint | When feature quota is exhausted |
|---|---|
| /keyword-research | Returns 429 QUOTA_EXCEEDED. Never spends credits — safe to loop. |
| /backlinks | Falls back to 1 credit per request. A deep query (page > 1 or limit > 100) always costs 1 credit. No credits → 402 PAYMENT_REQUIRED. |
| /site-audit | Returns 429 QUOTA_EXCEEDED when the monthly crawl count or the rolling page budget is used up. |
"cached": true in meta, and draws no feature quota or credits (it still counts as one API call).
3. Requests per minute
Separately from the monthly meters, your plan sets how many requests a minute you can make. This bounds a runaway loop or a leaked key to something recoverable — a monthly allowance says nothing about spending all of it inside an hour.
| Plan | Requests per minute |
|---|---|
| Pro | 20 |
| Agency | 60 |
Each endpoint counts separately, so working through your backlink allowance never locks you out of keyword research. Exceeding it returns 429 with retry_after (seconds) and limit in meta. Refused requests are not counted, so waiting out retry_after always clears it.
409 ALREADY_RUNNING; retry in a few seconds and it will be a cache hit.
Locations & Languages
/keyword-research accepts a location_code and language_code to localize results. Both are optional — the defaults are the United States (2840) and English (en).
location_code
A numeric market code. Common values:
| Code | Market | Code | Market |
|---|---|---|---|
| 2840 | United States | 2276 | Germany |
| 2826 | United Kingdom | 2250 | France |
| 2124 | Canada | 2724 | Spain |
| 2036 | Australia | 2380 | Italy |
| 2356 | India | 2528 | Netherlands |
| 2392 | Japan | 2076 | Brazil |
Over 90 markets are supported. An unrecognized code returns 422 UNSUPPORTED_LOCATION rather than falling back to the United States — being billed for American data you did not ask for is worse than being told the code is wrong. Call GET /api/v1/keyword-research/locations for the full list.
language_code
A two-letter language code. Supported values:
| Code | Language | Code | Language |
|---|---|---|---|
| en | English | pt | Portuguese |
| es | Spanish | nl | Dutch |
| fr | French | ru | Russian |
| de | German | ja | Japanese |
| it | Italian | zh | Chinese |
language_code falls back to English rather than returning an error — so double-check the code if results look unexpectedly English.
Error Codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | BAD_REQUEST | Malformed request syntax |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | API access not available on your plan (Pro or Agency required) |
| 404 | NOT_FOUND | Endpoint or resource not found |
| 402 | PAYMENT_REQUIRED | Feature quota exhausted and no credits remaining (backlinks) |
| 422 | VALIDATION_ERROR | Required parameter missing or invalid value |
| 409 | ALREADY_RUNNING | The same request is already being fetched for your account — retry shortly and it will be a cache hit. Nothing was charged |
| 429 | RATE_LIMITED / QUOTA_EXCEEDED | Monthly call limit, per-minute pacing or feature quota hit — see resets_at or retry_after in meta |
| 502 | UPSTREAM_ERROR | No data returned by the upstream data provider |
| 500 | SERVER_ERROR | Internal error — safe to retry |
MCP & LLM Clients
If your goal is to let an assistant like Claude read this data conversationally, you do not need to write a client. SignalSumo speaks the Model Context Protocol, which exposes the endpoints below as tools an LLM can call directly.
| Route | Auth | Best for |
|---|---|---|
| Hosted connector | OAuth 2.1 — no key to copy | Claude and other MCP clients. Nothing to install, always current. |
@signalsumo/mcp on npm | API key in the client config | Local installs, self-hosted setups, or running against your own environment. |
| This REST API | Authorization: Bearer | Your own scripts, dashboards and back-end integrations. |
All three read the same data through the same endpoints and the same plan limits — they differ only in how the caller authenticates. The npm package uses slightly different tool names from the hosted connector; its README is the reference for those. Source: github.com/signalsumo/mcp.
GET /api/v1/usage
Returns your API quota usage for the current calendar month.
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/usage"
Example Response
{
"success": true,
"data": {
"plan": "agency",
"api_calls_used": 42,
"api_calls_limit": 100,
"unlimited": false,
"resets_at": "2026-08-01"
},
"meta": {
"timestamp": "2026-06-26T10:00:00+00:00",
"key_name": "Production App"
}
}
GET /api/v1/backlinks
Returns a domain's backlink profile: a summary overview, distribution insights, and an enriched list of individual backlinks. Results are cached and shared with your dashboard (Pro: 2 days, Agency: 7 days); a cache hit is marked "cached": true and costs no feature quota.
This is the same data the Backlink Checker shows in the app, and the cache is shared — a domain you have already looked at there returns instantly here, free.
page > 1 or limit > 100 — always costs 1 credit. See Plans & Billing.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| domain | string | Yes | Root domain, e.g. example.com (a full URL is also accepted and normalized) |
| page | integer | No | Page number, default 1 |
| limit | integer | No | Results per page, 1–200, default 100 |
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/backlinks?domain=example.com&limit=2"
Example Response
{
"success": true,
"data": {
"domain": "example.com",
"total_backlinks": 48210,
"referring_domains": 1824,
"page": 1,
"limit": 2,
"overview": {
"domain_rank": 71,
"total_backlinks": 48210,
"referring_domains": 1824,
"referring_domains_nofollow": 640,
"referring_main_domains": 1610,
"referring_pages": 39044,
"referring_ips": 1502,
"referring_subnets": 1210,
"dofollow_backlinks": 1184,
"broken_backlinks": 220,
"broken_pages": 96,
"spam_score": 8,
"first_seen": "2018-05-11 09:20:00",
"lost_date": null
},
"insights": {
"referring_links_types": { "anchor": 30140, "image": 9800 },
"referring_links_attributes": { "noopener": 12000, "nofollow": 8400 },
"referring_links_platform_types": { "blogs": 900, "cms": 640, "news": 210 },
"referring_links_tld": { "com": 1200, "org": 180 },
"referring_links_countries": { "US": 800, "GB": 210 },
"referring_subnets": 1210,
"referring_main_domains": 1610
},
"backlinks": [
{
"domain_from": "blog.example-news.com",
"url_from": "https://blog.example-news.com/best-seo-tools",
"url_to": "https://example.com/",
"anchor": "SignalSumo",
"dofollow": 1,
"spam_score": 4,
"first_seen": "2021-03-10 12:00:00",
"last_seen": "2026-06-20 04:00:00",
"semantic_location": "article",
"platform_type": "blogs",
"country": "US",
"is_broken": 0,
"domain_from_rank": 62,
"page_from_rank": 41,
"is_lost": 0,
"lost_date": null,
"is_new": 0,
"item_type": "anchor",
"page_from_title": "The Best SEO Tools in 2026",
"page_from_status_code": 200,
"url_to_status_code": 200,
"domain_from_ip": "192.0.2.10",
"tld_from": "com",
"links_count": 2,
"is_indirect_link": 0,
"url_from_https": 1,
"attributes": ["noopener"],
"text_pre": "we recommend",
"text_post": "for site audits",
"kw_top3": 4,
"kw_top10": 12,
"kw_top100": 88
}
]
},
"meta": { "timestamp": "2026-06-26T10:00:00+00:00", "cached": false }
}
Backlink Fields
| Field | Description |
|---|---|
| domain_from / url_from | The linking site and the exact page the link is on |
| url_to | The page on your domain being linked to |
| anchor | Anchor text of the link |
| dofollow | 1 = dofollow, 0 = nofollow |
| spam_score | Spam score of the linking page (0–100) |
| domain_from_rank / page_from_rank | Authority of the linking domain / page, normalized 0–100 |
| is_new / is_lost / is_broken | Link lifecycle flags (1/0) |
| first_seen / last_seen / lost_date | When the link was first seen, last seen, and (if applicable) lost |
| platform_type / country / tld_from | Linking site's platform, country, and TLD |
| item_type | Link form: anchor, image, redirect, … |
| page_from_status_code / url_to_status_code | HTTP status of the linking page / the linked page |
| attributes | Link rel attributes, e.g. ["noopener","nofollow"] |
| kw_top3 / kw_top10 / kw_top100 | Keywords the linking page ranks for in the top 3 / 10 / 100 |
POST /api/v1/keyword-research
Returns a full metric set for a seed keyword — search volume, CPC, competition, difficulty, search intent, a 12-month volume trend, SERP features and more — plus a ranked list of related keywords carrying the same fields. Synchronous — responds immediately.
These are the metrics the Keyword Research Tool displays. Once you have picked the keywords worth pursuing, the Rank Tracker follows their positions daily — and /rank/keywords reads those positions back out, free.
429 QUOTA_EXCEEDED, so it's safe to call in a loop. Recent lookups are served from cache (marked "cached": true) at no quota cost.
Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
| keyword | string | Yes | Seed keyword, max 200 chars |
| location_code | integer | No | Location code, default 2840 (United States) |
| language_code | string | No | Language code, default en |
| limit | integer | No | Max related keywords returned, 1–100, default 10 |
Example Request
curl -X POST \
-H "Authorization: Bearer ss_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"keyword":"seo audit tool","limit":5}' \
"https://signalsumo.com/api/v1/keyword-research"
Example Response
{
"success": true,
"data": {
"keyword": "seo audit tool",
"location_code": 2840,
"language_code": "en",
"total_count": 80,
"overview": {
"search_volume": 2900,
"cpc": 19.07,
"competition": 0.11,
"competition_level": "LOW",
"difficulty": 77,
"intent": ["Commercial"],
"trend": [ { "y": 2026, "m": 5, "v": 2400 }, { "y": 2026, "m": 6, "v": 1600 } ],
"serp_features": ["organic"],
"growth": { "m": -33, "q": -16, "y": -64 },
"bid_low": 4.72,
"bid_high": 19.10,
"avg_backlinks": 5087,
"avg_ref_domains": 970,
"comp_domain_rank": 486,
"se_results": 41000000
},
"related_keywords": [
{
"keyword": "free seo audit tool",
"search_volume": 1900,
"cpc": 3.10,
"competition": 0.68,
"competition_level": "MEDIUM",
"difficulty": 54,
"intent": ["Commercial", "Transactional"],
"trend": [ { "y": 2026, "m": 6, "v": 1900 } ],
"serp_features": ["organic", "people_also_ask"],
"growth": { "m": 4, "q": -2, "y": 11 },
"bid_low": 1.20,
"bid_high": 4.90,
"avg_backlinks": 210,
"avg_ref_domains": 88,
"comp_domain_rank": 402,
"se_results": 12000000,
"related": ["website audit tool", "seo checker free"],
"match_bucket": "similar"
}
]
},
"meta": { "timestamp": "2026-06-26T10:00:00+00:00" }
}
Keyword Fields
The overview (seed keyword) and every related_keywords row share these fields. Any field may be null when the upstream data is unavailable.
| Field | Description |
|---|---|
| search_volume | Average monthly searches |
| cpc | Average cost-per-click (USD) |
| competition | Paid competition, 0–1 |
| competition_level | LOW / MEDIUM / HIGH |
| difficulty | Organic ranking difficulty, 0–100 (null if not yet computed) |
| intent | Search intent, e.g. ["Commercial"] |
| trend | 12-month volume history — { y, m, v } per month |
| growth | Volume change %: m monthly, q quarterly, y yearly |
| serp_features | SERP feature types present, e.g. ["organic","people_also_ask"] |
| bid_low / bid_high | Top-of-page bid range (USD) |
| avg_backlinks / avg_ref_domains | Average backlinks / referring domains of the pages ranking now |
| comp_domain_rank | Average authority (0–1000) of the pages ranking now |
| se_results | Total competing results for the keyword |
| related | Up to 8 related sub-keywords (related rows only) |
| match_bucket | Relation to the seed: similar, related, or question |
POST /api/v1/site-audit
Runs the same crawl as the Website Audit Tool — broken links, redirect chains, missing titles and canonical problems, page by page.
job_id immediately.
Poll GET /api/v1/jobs/{job_id} for results. Typical crawl time: 1–5 minutes.
Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | Full URL to crawl, e.g. https://example.com |
| max_pages | integer | No | Max pages to crawl (default 100). Capped by your plan's per-crawl limit and your remaining monthly page budget. |
| depth | integer | No | Crawl depth, 1–5, default 3 |
Example Request
curl -X POST \
-H "Authorization: Bearer ss_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","max_pages":50}' \
"https://signalsumo.com/api/v1/site-audit"
Response (202 Accepted)
{
"success": true,
"job_id": "a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5",
"status": "queued",
"poll": "https://signalsumo.com/api/v1/jobs/a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5",
"meta": { "timestamp": "2026-06-26T10:00:00+00:00" }
}
GET /api/v1/jobs/{job_id}
Poll the status of an async job. Poll every 10–15 seconds until status is complete or failed.
Status Values
| Status | Meaning |
|---|---|
| queued | Job accepted, not yet started |
| running | Crawl in progress — check progress (0–100) |
| complete | Done — data field contains results |
| failed | Crawl failed — error field has the reason |
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/jobs/a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5"
Response — Running
{
"success": true,
"data": {
"job_id": "a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5",
"endpoint": "site-audit",
"status": "running",
"progress": 42,
"created_at": "2026-06-26 10:00:00",
"updated_at": "2026-06-26 10:01:30",
"completed_at": null
},
"meta": { "timestamp": "2026-06-26T10:01:30+00:00" }
}
Response — Complete
{
"success": true,
"data": {
"job_id": "a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5",
"endpoint": "site-audit",
"status": "complete",
"progress": 100,
"created_at": "2026-06-26 10:00:00",
"updated_at": "2026-06-26 10:03:18",
"completed_at": "2026-06-26 10:03:18",
"data": {
"audit_id": "AUDIT-A1B2C3-4567",
"domain": "https://example.com",
"pages_crawled": 47,
"total_score": 78,
"geo_score": 71,
"issues": { "critical": 3, "warning": 12, "total": 15 },
"report_url": "https://signalsumo.com/report?id=AUDIT-A1B2C3-4567"
}
},
"meta": { "timestamp": "2026-06-26T10:03:18+00:00" }
}
GET /api/v1/rank/keywords
Every keyword your account tracks, each with the market and device it was measured in and its most recent position. This is the data behind the Rank Tracker — no crawl is triggered and nothing is charged.
country, language and device are returned on every row on purpose. A position is meaningless without them — comparing a desktop US ranking against a mobile UK one produces a decline that never happened.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | No | Restrict to one project. Omit to return keywords across every project you own. |
| limit | integer | No | 1–500, default 100 |
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/rank/keywords?limit=1"
Example Response
{
"success": true,
"data": {
"keywords": [
{
"keyword_id": 4821,
"keyword": "seo audit tool",
"difficulty": 62,
"search_volume": 8100,
"cpc": 12.4,
"country": "US",
"language": "en",
"device": "desktop",
"status": "active",
"project_id": 17,
"project_domain": "example.com",
"project_name": "Example Site",
"last_checked": "2026-08-19",
"current_position": 8,
"previous_position": 11,
"position_change": 3,
"landing_page": "https://example.com/tools/audit",
"gsc_clicks": 143,
"gsc_impressions": 5210,
"gsc_ctr": 2.74,
"local_pack": false,
"featured_snippet": true,
"ai_overview": false
}
],
"count": 1
},
"meta": { "project_id": null, "limit": 1 }
}
position_change is positive when the keyword moved up. A keyword that has never been checked returns null for every latest.* field rather than 0 — position zero would read as "ranked first".
GET /api/v1/rank/history
Daily position history for one tracked keyword, with the URL that ranked and the SERP features present on each check. Includes a precomputed trend summary.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| keyword_id | integer | Yes | From /rank/keywords. A keyword you do not own returns 404 NOT_FOUND. |
| days | integer | No | 1–365, default 90 |
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/rank/history?keyword_id=4821&days=30"
Example Response
{
"success": true,
"data": {
"keyword": {
"id": 4821,
"keyword": "seo audit tool",
"project_id": 17,
"domain": "example.com",
"project": "Example Site"
},
"history": [
{
"check_date": "2026-08-19",
"position": 8,
"previous_position": 11,
"change": 3,
"landing_page": "https://example.com/tools/audit",
"gsc_clicks": 143,
"gsc_impressions": 5210,
"gsc_ctr": 2.74,
"gsc_average_position": 8.6,
"featured_snippet": true,
"ai_overview": false,
"people_also_ask": true,
"local_pack": false,
"images": false,
"videos": false,
"shopping": false,
"knowledge_graph": false,
"sitelinks": true
}
],
"trend": { "first": 14, "latest": 8, "best": 6, "worst": 15 }
},
"meta": { "days_requested": 30, "points": 1 }
}
Reading trend
| Field | Meaning |
|---|---|
| first | Position at the oldest point in the window |
| latest | Position at the most recent check |
| best | Lowest number reached (best ranking) |
| worst | Highest number reached (worst ranking) |
history is ordered newest first. best and worst ignore unranked checks, so they are null when the keyword never ranked in the window.
GET /api/v1/gsc/properties
The Google Search Console properties connected to your account, as shown in Search Console Insights. Takes no parameters.
This reads SignalSumo's synced copy — it does not call Google. last_synced_at tells you how fresh that copy is.
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/gsc/properties"
Example Response
{
"success": true,
"data": {
"properties": [
{
"property_id": 31,
"property_uri": "sc-domain:example.com",
"display_name": "example.com",
"status": "active",
"last_synced_at": "2026-08-20 04:15:02",
"last_sync_status": "ok",
"google_email": "[email protected]",
"is_sandbox": false
}
],
"count": 1
}
}
GET /api/v1/gsc/queries
Clicks, impressions, CTR and average position for a synced property, grouped by whichever dimension you ask for. Despite the name it is not limited to queries — set dim to break the same numbers down by page, country, device or date.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| property_id | integer | Yes | From /gsc/properties. A property you do not own returns 404 NOT_FOUND. |
| dim | string | No | query (default), page, country, device, date, searchAppearance |
| from | string | No | YYYY-MM-DD, default 28 days ago |
| to | string | No | YYYY-MM-DD, default today |
| sort | string | No | clicks (default), impressions, ctr, position, key |
| dir | string | No | desc (default) or asc |
| limit | integer | No | 1–500, default 100 |
422 VALIDATION_ERROR, but an unrecognised dim or sort value silently falls back to the default rather than erroring. Check the dim echoed back in data before trusting a breakdown.
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/gsc/queries?property_id=31&dim=query&limit=2"
Example Response
{
"success": true,
"data": {
"property_id": 31,
"dim": "query",
"from": "2026-07-23",
"to": "2026-08-20",
"totals": {
"clicks": 4820,
"impressions": 216400,
"ctr": 2.23,
"position": 18.4
},
"rows": [
{ "key": "seo audit tool", "clicks": 143, "impressions": 5210, "ctr": 2.74, "position": 8.6 },
{ "key": "free seo checker", "clicks": 98, "impressions": 7740, "ctr": 1.27, "position": 14.2 }
],
"total_rows": 1842
},
"meta": { "sort": "clicks", "dir": "desc", "limit": 2 }
}
total_rows is the number of distinct keys in the period, not the number returned — use it to decide whether to raise limit. totals always covers the whole period regardless of limit.
GET /api/v1/ai-visibility/projects
The brands you track across AI answer engines, one row per project, with the current visibility score and its movement. Takes no parameters. Powered by the AI Visibility Checker.
Scores are collected by scheduled scans, so this endpoint never calls an AI provider — it returns what the last scan stored.
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/ai-visibility/projects"
Example Response
{
"success": true,
"data": {
"projects": [
{
"id": 9,
"domain": "example.com",
"brand_name": "Example",
"target_country": "US",
"target_language": "en",
"ai_engine": "all",
"tracking_frequency": "weekly",
"status": "active",
"visibility_score": 41.8,
"previous_visibility_score": 37.2,
"score_change": 4.6,
"created_at": "2026-05-02 11:20:44",
"updated_at": "2026-08-18 06:02:11"
}
],
"count": 1
}
}
score_change is null until a project has been scanned at least twice — a first scan has nothing to compare against, and reporting 0 would read as "no movement".
GET /api/v1/ai-visibility/share-of-voice
How often AI assistants name your brand versus the competitors tracked alongside it, plus the full metric breakdown from the most recent scan.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | Yes | From /ai-visibility/projects. A project you do not own returns 404 NOT_FOUND. |
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/ai-visibility/share-of-voice?project_id=9"
Example Response
{
"success": true,
"data": {
"project": {
"id": 9,
"domain": "example.com",
"brand_name": "Example",
"target_country": "US",
"ai_engine": "all",
"visibility_score": 41.8,
"previous_visibility_score": 37.2
},
"latest_snapshot": {
"geo_score": 41.8,
"mention_rate": 38.0,
"avg_position": 2.4,
"sentiment_avg": 0.62,
"citation_rate": 21.5,
"competition_score": 58.3,
"prompts_evaluated": 50,
"snapshot_date": "2026-08-18"
},
"share_of_voice": {
"brand_mentions": 19,
"competitor_mentions": 74,
"total_mentions": 93,
"brand_share_pct": 20.43
},
"competitors": [
{
"competitor_name": "Competitor One",
"competitor_domain": "competitor1.com",
"mention_count": 31,
"visibility_score": 52.1,
"avg_position": 1.9,
"updated_at": "2026-08-18 04:41:07"
}
]
}
}
Two different percentages
These are easy to confuse, and they answer different questions:
| Field | Question it answers |
|---|---|
mention_rate | Of the prompts we tested, what share mentioned you at all? — coverage. |
brand_share_pct | Of every brand mention across you and your tracked competitors, what share was yours? — competitive position. |
latest_snapshot is null before a project's first scan completes. competitors returns at most 20, ordered by mention count. brand_share_pct is null when no mentions have been recorded on either side — a share of nothing is not zero percent.
GET /api/v1/keyword-research/locations
Every market POST /keyword-research accepts, so you can discover a location_code instead of guessing one and earning a 422. Takes no parameters.
Example Request
curl -H "Authorization: Bearer ss_live_xxxx" \
"https://signalsumo.com/api/v1/keyword-research/locations"
Example Response
{
"success": true,
"data": {
"locations": [
{ "location_code": 2840, "location_name": "United States", "country_iso": "US", "language_code": "en" },
{ "location_code": 2826, "location_name": "United Kingdom", "country_iso": "GB", "language_code": "en" }
],
"count": 94,
"note": "These are the markets covered by the keyword database. Pass location_code to POST /keyword-research."
}
}
Changelog
| Version | Date | Changes |
|---|---|---|
| v1.2 | Aug 2026 | Documented the seven read-only endpoints that were already live: /rank/keywords, /rank/history, /gsc/properties, /gsc/queries, /ai-visibility/projects, /ai-visibility/share-of-voice and /keyword-research/locations. No behaviour changed — these were callable before, just undocumented. Added MCP and LLM client guidance. |
| v1.1 | Jul 2026 | Keyword & backlink responses expanded to full metric sets (difficulty, intent, trend, SERP features, enriched backlink fields, overview & insights). Site-audit results add geo_score and issue counts. Added location/language reference and billing details. |
| v1.0 | Jun 2026 | Initial release — usage, backlinks, keyword-research, site-audit, jobs |
Questions? Email [email protected]