Google Search Console
Read connection status, query GSC search-analytics performance, and run URL inspections — /seo/gsc/connect, /performance, /inspect-urls.
Three endpoints for a project that has connected a Google Search Console property.
Not connected is a 200, not an error
When a project is not connected, or its token expired, performance and inspect-urls return HTTP 200 with { "ok": false, … } and a connectUrl — not an error status — so a client can prompt the user to reconnect without special-casing a failure. Always check ok before reading rows or results.
Connection status
/seo/gsc/connectThis reads status — it does not start OAuth
Despite the name, this endpoint does not redirect into Google's consent screen. It reports whether a grant already exists. The OAuth callback lives at /api/gsc/oauth/callback, outside the /seo/* surface; start the flow from the MisarSEO dashboard.
Not rate limited.
Query parameters
projectIdstringqueryrequiredOwning project.
Response fields
hasGrantbooleanWhether a usable Search Console grant exists for this project.
connectionobject | null{ siteUrl, connectedAccountEmail, connectedAt }, or null when no grant exists.
curl "https://api.misar.io/seo/gsc/connect?projectId=5b1c7d2e-…" \
-H "Authorization: Bearer $MISARSEO_API_KEY"{
"hasGrant": true,
"connection": {
"siteUrl": "sc-domain:acme.com",
"connectedAccountEmail": "jane@example.com",
"connectedAt": "2026-06-11T14:02:19.000Z"
}
}{ "hasGrant": false, "connection": null }Performance
/seo/gsc/performanceSearch-analytics rows for the connected property. Charges no credits.
Request body
projectIdstringbodyrequiredOwning project.
dimensionsstring[]bodydefault: ["query"]Any of query, page, country, device, date, searchAppearance. Unrecognised entries are dropped.
dateRangestringbodyA preset window — one of last_7_days, last_28_days, last_3_months, last_6_months, last_12_months, last_16_months. An alternative to explicit dates.
startDatestringbodyYYYY-MM-DD. Use with endDate instead of dateRange.
endDatestringbodyYYYY-MM-DD.
filtersArray<{dimension, operator?, expression}>bodyoperator is one of equals, notEquals, contains, notContains, defaulting to equals.
typestringbodySearch type — one of web, image, video, news, googleNews, discover.
dataStatestringbodyall to include fresh, not-yet-finalised data; final for finalised data only.
rowLimitnumberbodydefault: 1000Clamped to between 1 and 1000.
startRownumberbodyOffset for pagination. Must be 0 or greater.
Response fields
okbooleanfalse means not connected — read reason and connectUrl instead of rows.
siteUrlstringThe connected property.
rowsobject[]{ keys, clicks, impressions, ctr, position } per row.
rowCountnumberRows in this response.
hasMorebooleanWhether more rows are available.
nextStartRownumberPass back as startRow to fetch the next page. Present only when hasMore is true.
curl -X POST https://api.misar.io/seo/gsc/performance \
-H "Authorization: Bearer $MISARSEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "5b1c7d2e-…",
"dimensions": ["query"],
"dateRange": "last_28_days",
"type": "web",
"dataState": "final",
"rowLimit": 1000
}'{
"ok": true,
"siteUrl": "sc-domain:acme.com",
"startDate": "2026-07-07",
"endDate": "2026-08-03",
"dimensions": ["query"],
"rowCount": 1000,
"rows": [
{ "keys": ["seo tools"], "clicks": 42, "impressions": 800, "ctr": 0.0525, "position": 7.1 }
],
"hasMore": true,
"nextStartRow": 1000
}{
"ok": false,
"reason": "Search Console is not connected for this project.",
"connectUrl": "/api/seo/gsc/connect?projectId=5b1c7d2e-…",
"setupDocsUrl": "https://docs.misar.io/seo/gsc"
}Rate limit: 20 requests per 60 s.
The field is `type`, not `searchType`
Google's own API calls this searchType, but this endpoint reads type. A body sending searchType is silently ignored — no error, just unfiltered results. Rename the field when porting code written against Google's API directly.
URL inspection
/seo/gsc/inspect-urlsInspects up to 50 URLs against the connected property. Failures are reported per URL rather than failing the batch.
Request body
projectIdstringbodyrequiredOwning project.
urlsstring[]bodyrequiredBetween 1 and 50 URLs. Each must parse and use the http: or https: scheme.
languageCodestringbodydefault: en-USBCP-47 language code for the inspection results.
Response fields
okbooleanfalse means not connected — read reason and connectUrl.
siteUrlstringThe connected property.
resultsArray<{url, result?, error?}>One entry per URL. A per-URL failure carries error instead of result.
curl -X POST https://api.misar.io/seo/gsc/inspect-urls \
-H "Authorization: Bearer $MISARSEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "5b1c7d2e-…",
"urls": ["https://acme.com/", "https://acme.com/pricing"]
}'{
"ok": true,
"siteUrl": "sc-domain:acme.com",
"results": [
{ "url": "https://acme.com/", "result": { "indexStatusResult": { "verdict": "PASS" } } },
{ "url": "https://acme.com/pricing", "error": "Inspection failed" }
]
}{ "error": "URL scheme must be http or https: ftp://acme.com", "code": "VALIDATION_ERROR" }Rate limit: 10 requests per 60 s.
Status codes
| Code | Meaning |
|---|---|
200 | Data returned, or { "ok": false } because the property is not connected |
400 | VALIDATION_ERROR — missing projectId, an unparseable URL, a non-HTTP scheme, or more than 50 URLs |
401 | UNAUTHENTICATED |
404 | NOT_FOUND — project not found |
429 | RATE_LIMITED |
Limits
| Limit | Value |
|---|---|
rowLimit | 1–1000 |
| URLs per inspection request | 50 |
| Performance rate limit | 20 / 60 s |
| Inspection rate limit | 10 / 60 s |