# Seo · Management API

> Management API reference for seo: GET /sites/{id}/seo/search-console, POST /sites/{id}/seo/search-console/verify.

> Markdown version of https://kanorio.com/en/developers/management-api/seo. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp

Base URL: `https://app.kanorio.com/api/v1` · [Errors](https://kanorio.com/en/developers/basics/errors) · [Pagination](https://kanorio.com/en/developers/basics/pagination)

### Search console status

`GET /sites/{id}/seo/search-console`

- Stability: beta
- Permission: `seo:view`
- Rate limit: default (120/minute per token)
- MCP tool: `seo_search_console_status`

Report the Google Search Console connection for a website: whether a Google account is connected, which property and sitemap Kanorio uses, whether ownership is verified and how, when the sitemap was last submitted, and whether a re-verification is pending. Connecting a Google account is a browser OAuth step the owner must do under SEO › Settings; this capability cannot connect. Use it before seo.search_console.verify_and_submit, and to explain the next step to the owner when lastFailureCode is OWNERSHIP_REQUIRED (verify the domain in Search Console), SITEMAP_NOT_REACHABLE (fix the external frontend's /sitemap.xml) or DNS_NOT_PROPAGATED (just wait). Errors: FORBIDDEN (also when the website does not exist).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Website id. Get it from sites.list or from sites.create. |

**Response** (200)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `connected` | boolean | yes | A Google account is connected (refresh token present). |
| `email` | string \| null | yes | Connected Google account email. |
| `propertyUrl` | string \| null | yes | Search Console property that is (or will be) used, e.g. https://www.example.com/. Follows externalStorefrontUrl for HEADLESS sites, otherwise the primary custom domain or the Kanorio subdomain. |
| `sitemapUrl` | string \| null | yes | Sitemap URL that is (or will be) submitted. |
| `verified` | boolean | yes | Ownership verified via Kanorio at least once. |
| `ownershipSource` | "meta" \| "existing" \| "dns" \| null | yes | How ownership was verified: "meta" (verification tag on Kanorio-rendered pages, HOSTED), "existing" (the Google account already owned a covering property), "dns" (Kanorio wrote a TXT record to its managed DNS zone). null until verified. |
| `sitemapSubmittedAt` | string \| null | yes | ISO time of the last successful sitemap submission. |
| `needsReverify` | boolean | yes | True when the property changed (domain or externalStorefrontUrl) or the last automatic verification failed; call seo.search_console.verify_and_submit. |
| `lastFailureCode` | string \| null | yes | Classification of the last failed verification (e.g. OWNERSHIP_REQUIRED, DNS_NOT_PROPAGATED, SITEMAP_NOT_REACHABLE); null when the last attempt succeeded. |
| `observable` | boolean | yes | The site has a public URL to verify (HOSTED: published; HEADLESS: externalStorefrontUrl set). False means verify_and_submit would return NO_PUBLIC_URL. |

**Errors**

| Code | Status | When |
| --- | --- | --- |
| `FORBIDDEN` | 403 | also when the website does not exist |

```bash
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/seo/search-console" \
  -H "Authorization: Bearer $KANORIO_TOKEN"
```

```json
{
  "connected": true,
  "email": "owner@sunnybakery.example",
  "propertyUrl": "https://www.sunnybakery.example/",
  "sitemapUrl": "https://www.sunnybakery.example/sitemap.xml",
  "verified": true,
  "ownershipSource": "meta",
  "sitemapSubmittedAt": "2026-10-01T02:30:00.000Z",
  "needsReverify": false,
  "lastFailureCode": null,
  "observable": true
}
```

### Verify and submit

`POST /sites/{id}/seo/search-console/verify`

- Stability: beta
- Permission: `seo:manage`
- Rate limit: heavy (20/minute per token, plus 20/minute per site)
- MCP tool: `seo_search_console_verify_and_submit`

Verify ownership of the website's current property in Google Search Console, add the property, and submit the sitemap. Same flow as the dashboard's Check again button. HOSTED sites verify with a meta tag Kanorio renders. HEADLESS sites with externalStorefrontUrl first check whether the connected Google account already owns a covering property; if not and the domain's DNS is managed by Kanorio, Kanorio writes a TXT record and verifies via DNS; otherwise the owner must verify the domain in Search Console themselves. Requires a connected Google account (owner does this in the dashboard) and a public URL. On failure the site is marked needsReverify and a background job keeps retrying transient causes (META_NOT_LIVE, DNS_NOT_PROPAGATED), but not OWNERSHIP_REQUIRED or SITEMAP_NOT_REACHABLE, which need the owner. Errors: FORBIDDEN, NO_PUBLIC_URL, SEARCH_CONSOLE_NOT_CONNECTED, META_NOT_LIVE (retry in 20-30 s), OWNERSHIP_REQUIRED, SITEMAP_NOT_REACHABLE, DNS_NOT_PROPAGATED (retry later), SEARCH_CONSOLE_AUTH_EXPIRED, SEARCH_CONSOLE_PERMISSION_DENIED, SEARCH_CONSOLE_QUOTA_EXCEEDED, SEARCH_CONSOLE_PROPERTY_NOT_FOUND, SEARCH_CONSOLE_UNAVAILABLE, SEARCH_CONSOLE_ERROR.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Website id. Get it from sites.list or from sites.create. |

**Response** (200)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `propertyUrl` | string | yes | — |
| `sitemapUrl` | string | yes | — |
| `sitemapSubmittedAt` | string | yes | ISO time of this submission. |
| `ownershipSource` | "meta" \| "existing" \| "dns" | yes | — |

**Errors**

| Code | Status | When |
| --- | --- | --- |
| `FORBIDDEN` | 403 | — |
| `NO_PUBLIC_URL` | 422 | — |
| `SEARCH_CONSOLE_NOT_CONNECTED` | 422 | — |
| `META_NOT_LIVE` | 422 | retry in 20-30 s |
| `OWNERSHIP_REQUIRED` | 422 | — |
| `SITEMAP_NOT_REACHABLE` | 422 | — |
| `DNS_NOT_PROPAGATED` | 422 | retry later |
| `SEARCH_CONSOLE_AUTH_EXPIRED` | 422 | — |
| `SEARCH_CONSOLE_PERMISSION_DENIED` | 422 | — |
| `SEARCH_CONSOLE_QUOTA_EXCEEDED` | 429 | — |
| `SEARCH_CONSOLE_PROPERTY_NOT_FOUND` | 422 | — |
| `SEARCH_CONSOLE_UNAVAILABLE` | 503 | — |
| `SEARCH_CONSOLE_ERROR` | 502 | — |

```bash
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/seo/search-console/verify" \
  -H "Authorization: Bearer $KANORIO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```json
{
  "propertyUrl": "https://www.sunnybakery.example/",
  "sitemapUrl": "https://www.sunnybakery.example/sitemap.xml",
  "sitemapSubmittedAt": "2026-10-06T08:00:00.000Z",
  "ownershipSource": "meta"
}
```
