Get all websites in one call
GET
/portfolio- Scope
sites:read- MCP tool
portfolio
Every website in one call, with scores and changes The Websites list of the app as data, sorted by name. A website key sees only its website. `search` (28 days against the 28 before) is only there for keys with search:read.
Parameters
| Name | In | Details |
|---|---|---|
page | query | integerdefault 1, min 1Page number, from 1. |
per | query | integerdefault 50, min 1, max 200Rows per page, 1 to 200. |
Response
200 · application/json
| Field | Details |
|---|---|
total | integer · required; Rows that match, over all pages |
page | integer · required; This page, from 1 |
per | integer · required; Rows per page |
hasMore | true or false · required; More rows after this page |
websites | list of object · required |
websites[].id | string · required; Website id |
websites[].name | string · required; Website name |
websites[].host | string · required; Host name, without www. |
websites[].url | address (URL) · required; Home page address |
websites[].platform | wordpress | astro | shopify | webflow | other | unknown · required; What the website runs on |
websites[].status | new | auditing | ready | paused · required; Website state; a paused website gets no scheduled audits |
websites[].score | object or null · required; Latest score; null before the first audit |
websites[].score.site | integer or null · required; Site score, 0 to 100; null until enough is measured |
websites[].score.health | integer or null · required; Health score, 0 to 100; null until enough is measured |
websites[].score.aeo | integer or null · required; AEO readiness, 0 to 100; null until enough is measured |
websites[].score.coverage | number · required; Share of the website that could be measured, 0 to 1 |
websites[].score.confidence | high | medium | low · required; How sure the score is |
websites[].score.version | string · required; Score formula version |
websites[].score.computedAt | string · required; When it was computed |
websites[].score.categories | object · required; Score per category (Technical, On-page, Internal linking and Performance); null where too little was measured |
websites[].score.categories.Technical | number |
websites[].score.categories.On-page | number |
websites[].score.categories.Internal linking | number |
websites[].score.categories.Performance | number |
websites[].previousAudit | object · required; Score the full audit before the latest one computed |
websites[].previousAudit.site | number |
websites[].previousAudit.health | number |
websites[].previousAudit.aeo | number |
websites[].previousAudit.computedAt | string |
websites[].lastWeek | object · required; Latest score at least 7 days old |
websites[].lastWeek.site | number |
websites[].lastWeek.health | number |
websites[].lastWeek.aeo | number |
websites[].lastWeek.computedAt | string |
websites[].change | object · required; Differences in points |
websites[].change.sincePreviousAudit | object · required |
websites[].change.sincePreviousAudit.site | number |
websites[].change.sincePreviousAudit.health | number |
websites[].change.sincePreviousAudit.aeo | number |
websites[].change.sincePreviousAudit.since | string |
websites[].change.sinceLastWeek | object · required |
websites[].change.sinceLastWeek.site | number |
websites[].change.sinceLastWeek.health | number |
websites[].change.sinceLastWeek.aeo | number |
websites[].change.sinceLastWeek.since | string |
websites[].issues | object · required |
websites[].issues.open | integer · required; Open audit findings |
websites[].issues.critical | integer · required; Open critical findings |
websites[].issues.newThisWeek | integer · required; Found in the last 7 days |
websites[].actions | object · required |
websites[].actions.open | integer · required; Open actions, keyword tasks included |
websites[].actions.waiting | integer · required; Open 14 days or more |
websites[].lastAudit | object or null · required; Last finished full audit |
websites[].lastAudit.id | string · required; Audit id |
websites[].lastAudit.finishedAt | string or null · required |
websites[].lastAudit.pagesCrawled | integer · required; Pages read |
websites[].lastAudit.partialReason | string or null · required; Why the audit stopped early (page or time budget, cancelled); null when complete |
websites[].lastAudit.coverage | object or null · required; Sitemap coverage; null without a sitemap |
websites[].lastAudit.coverage.sitemapUrls | integer · required; Addresses in the sitemap |
websites[].lastAudit.coverage.sitemapCrawled | integer · required; Of those, read |
websites[].lastAudit.coverage.percent | integer · required; Share read, 0 to 100 |
websites[].running | object or null · required; A crawl queued or running now |
websites[].nextScheduledAuditAt | string or null · required; Next weekly audit; null for a paused website |
websites[].search | object · search:read keys only. { connected: false } without Search Console. |
websites[].search.connected | true or false · required; Search Console is connected |
websites[].search.stale | true or false · Search Console data stopped updating |
websites[].search.clicks | integer · Clicks, last 28 days |
websites[].search.impressions | integer · Impressions, last 28 days |
websites[].search.previousClicks | integer · Clicks, the 28 days before |
websites[].search.previousImpressions | integer · Impressions, the 28 days before |
websites[].search.clicksChangePct | number or null · Change in percent; null when the period before had none |
websites[].search.impressionsChangePct | number or null · Change in percent; null when the period before had none |
websites[].link | address (URL) · required; The website in the app |
searchPeriod | object · The days `search` covers (search:read keys only) |
searchPeriod.days | integer · required; Days in the period (28) |
searchPeriod.from | date (YYYY-MM-DD) · required |
searchPeriod.to | date (YYYY-MM-DD) · required |
searchPeriod.previousFrom | date (YYYY-MM-DD) · required |
searchPeriod.previousTo | date (YYYY-MM-DD) · required |
note | string · required; How to read the numbers |
Errors
| Status | Meaning |
|---|---|
400 | Bad request. Codes: bad_page, bad_per. |
401 | Missing, unknown or revoked key. Codes: missing_key, invalid_key. |
403 | The key lacks the scope, covers another website, or its owner lost access. Codes: missing_scope, other_site, owner_left, no_owner, forbidden. |
429 | Too many requests this hour for this key. Codes: rate_limited. |
Example request
curl \
-H "Authorization: Bearer mr_ws_…" \
"https://app.monoranks.com/api/v1/portfolio"const res = await fetch("https://app.monoranks.com/api/v1/portfolio", {
headers: { Authorization: "Bearer mr_ws_…" },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();import requests
res = requests.get(
"https://app.monoranks.com/api/v1/portfolio",
headers={"Authorization": "Bearer mr_ws_…"},
)
res.raise_for_status()
data = res.json()<?php
$ch = curl_init("https://app.monoranks.com/api/v1/portfolio");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer mr_ws_…"],
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);import axios from "axios";
const { data } = await axios.get("https://app.monoranks.com/api/v1/portfolio", { headers: { Authorization: "Bearer mr_ws_…" } });Example response
{
"total": 1,
"page": 1,
"per": 50,
"hasMore": false,
"websites": [
{
"id": "3f6c2a1e-8b4d-4c7a-9e21-5d0b7a6f4c13",
"name": "Acme Bikes",
"host": "acmebikes.com",
"url": "https://acmebikes.com/",
"platform": "wordpress",
"status": "ready",
"score": {
"site": 78,
"health": 81,
"aeo": 69,
"coverage": 0.92,
"confidence": "high",
"version": "1.1.0",
"computedAt": "2026-10-04T02:41:12.000Z",
"categories": {
"Technical": 84,
"On-page": 76,
"Internal linking": 88,
"Performance": 71
}
},
"previousAudit": {
"site": 74,
"health": 77,
"aeo": 66,
"computedAt": "2026-09-27T02:38:40.000Z"
},
"lastWeek": {
"site": 74,
"health": 77,
"aeo": 66,
"computedAt": "2026-09-27T02:38:40.000Z"
},
"change": {
"sincePreviousAudit": {
"site": 4,
"health": 4,
"aeo": 3,
"since": "2026-09-27T02:38:40.000Z"
},
"sinceLastWeek": {
"site": 4,
"health": 4,
"aeo": 3,
"since": "2026-09-27T02:38:40.000Z"
}
},
"issues": {
"open": 14,
"critical": 1,
"newThisWeek": 2
},
"actions": {
"open": 17,
"waiting": 5
},
"lastAudit": {
"id": "d4f6a8c0-2e4a-4c6e-8a0c-4e6a8c0e2a4b",
"finishedAt": "2026-10-04T02:40:55.000Z",
"pagesCrawled": 186,
"partialReason": null,
"coverage": {
"sitemapUrls": 180,
"sitemapCrawled": 176,
"percent": 98
}
},
"running": null,
"nextScheduledAuditAt": "2026-10-11T02:00:00.000Z",
"search": {
"connected": true,
"stale": false,
"clicks": 4210,
"impressions": 168300,
"previousClicks": 3890,
"previousImpressions": 151200,
"clicksChangePct": 8.2,
"impressionsChangePct": 11.3
},
"link": "https://app.monoranks.com/sites/3f6c2a1e-8b4d-4c7a-9e21-5d0b7a6f4c13/overview"
}
],
"searchPeriod": {
"days": 28,
"from": "2026-09-06",
"to": "2026-10-03",
"previousFrom": "2026-08-09",
"previousTo": "2026-09-05"
},
"note": "One row per website the key covers, sorted by name."
}{
"error": {
"code": "bad_page",
"message": "page must be a whole number from 1 to 10000."
}
}{
"error": {
"code": "missing_key",
"message": "Send the key as Authorization: Bearer mr_site_…"
}
}{
"error": {
"code": "missing_scope",
"message": "This key does not have the scope this call needs."
}
}{
"error": {
"code": "rate_limited",
"message": "More than 1200 requests this hour for this key."
}
}The MCP server does the same with the tool portfolio.