MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarDevMisarCoderMisarSEOMisar PlatformMisar SSO
API Reference

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

GET/seo/gsc/connect

This 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

projectIdstringqueryrequired

Owning project.

Response fields

hasGrantboolean

Whether a usable Search Console grant exists for this project.

connectionobject | null

{ siteUrl, connectedAccountEmail, connectedAt }, or null when no grant exists.

Request
curl "https://api.misar.io/seo/gsc/connect?projectId=5b1c7d2e-…" \
  -H "Authorization: Bearer $MISARSEO_API_KEY"
200 — Connected
{
  "hasGrant": true,
  "connection": {
    "siteUrl": "sc-domain:acme.com",
    "connectedAccountEmail": "jane@example.com",
    "connectedAt": "2026-06-11T14:02:19.000Z"
  }
}
200 — Not connected
{ "hasGrant": false, "connection": null }

Performance

POST/seo/gsc/performance

Search-analytics rows for the connected property. Charges no credits.

Request body

projectIdstringbodyrequired

Owning project.

dimensionsstring[]bodydefault: ["query"]

Any of query, page, country, device, date, searchAppearance. Unrecognised entries are dropped.

dateRangestringbody

A 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.

startDatestringbody

YYYY-MM-DD. Use with endDate instead of dateRange.

endDatestringbody

YYYY-MM-DD.

filtersArray<{dimension, operator?, expression}>body

operator is one of equals, notEquals, contains, notContains, defaulting to equals.

typestringbody

Search type — one of web, image, video, news, googleNews, discover.

dataStatestringbody

all to include fresh, not-yet-finalised data; final for finalised data only.

rowLimitnumberbodydefault: 1000

Clamped to between 1 and 1000.

startRownumberbody

Offset for pagination. Must be 0 or greater.

Response fields

okboolean

false means not connected — read reason and connectUrl instead of rows.

siteUrlstring

The connected property.

rowsobject[]

{ keys, clicks, impressions, ctr, position } per row.

rowCountnumber

Rows in this response.

hasMoreboolean

Whether more rows are available.

nextStartRownumber

Pass back as startRow to fetch the next page. Present only when hasMore is true.

Request
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
  }'
200 — OK
{
  "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
}
200 — Not connected
{
  "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

POST/seo/gsc/inspect-urls

Inspects up to 50 URLs against the connected property. Failures are reported per URL rather than failing the batch.

Request body

projectIdstringbodyrequired

Owning project.

urlsstring[]bodyrequired

Between 1 and 50 URLs. Each must parse and use the http: or https: scheme.

languageCodestringbodydefault: en-US

BCP-47 language code for the inspection results.

Response fields

okboolean

false means not connected — read reason and connectUrl.

siteUrlstring

The connected property.

resultsArray<{url, result?, error?}>

One entry per URL. A per-URL failure carries error instead of result.

Request
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"]
  }'
200 — OK
{
  "ok": true,
  "siteUrl": "sc-domain:acme.com",
  "results": [
    { "url": "https://acme.com/", "result": { "indexStatusResult": { "verdict": "PASS" } } },
    { "url": "https://acme.com/pricing", "error": "Inspection failed" }
  ]
}
400 — Bad scheme
{ "error": "URL scheme must be http or https: ftp://acme.com", "code": "VALIDATION_ERROR" }

Rate limit: 10 requests per 60 s.

Status codes

CodeMeaning
200Data returned, or { "ok": false } because the property is not connected
400VALIDATION_ERROR — missing projectId, an unparseable URL, a non-HTTP scheme, or more than 50 URLs
401UNAUTHENTICATED
404NOT_FOUND — project not found
429RATE_LIMITED

Limits

LimitValue
rowLimit1–1000
URLs per inspection request50
Performance rate limit20 / 60 s
Inspection rate limit10 / 60 s