REST API

Last updated

Everything your account stores is readable over HTTPS with a key from your account, Keys tab: the same rw_ keys the MCP server takes, with the same scopes. The API returns stored data and adds to your own lists; it never spends on DataForSEO or credits. Runs that spend (the agent, Why, keyword research, the writer) live in the MCP server, where every answer carries its cost line.

Authentication and scopes

curl https://rankwhy.com/api/v1/me \
  -H "Authorization: Bearer rw_your_key"

read covers every GET. research is needed for the POSTs below (they add to your watchlist, calendar and tasks). A key without the scope gets 403 with the scope named. A missing or revoked key gets 401 with a WWW-Authenticate: Bearer challenge.

Limits and pagination

Per account: 200 requests a minute, 5,000 an hour, 50,000 a day; over the limit the answer is 429 with Retry-After: 60. Lists take ?limit= (default 50, at most 200) and ?offset= and answer { data, meta: { limit, offset, total } }; single objects answer { data }; errors answer { error }.

Endpoints

Method and pathScopeReturns
GET /api/v1/mereadthe key's name, scopes and the limits
GET /api/v1/sitesreadevery domain the account has data for: calendar site, watched keyword count, Search Console window
GET /api/v1/jobs, GET /api/v1/jobs/:idreadagent jobs (intent, patterns, pages, costs)
GET /api/v1/watchreadthe memory digest: every watched keyword with its position now and before, the events and dates
POST /api/v1/watchresearchadds { keyword, locationCode, languageCode, site? } to the watchlist
GET /api/v1/calendar?month=YYYY-MM, GET /api/v1/calendar/entries/:idreadplanned and finished days; one entry carries the article (draft Markdown, lint, citations) or the refresh diff
POST /api/v1/calendar/entriesresearchplans { keyword, locationCode, languageCode, site, scheduledOn, kind?, url? }
GET /api/v1/guard?site=readSite Guard: pages short of their position's clicks, length findings, split queries with winner and redirects, your curve's source
GET /api/v1/coverage?site=readevery known keyword with ranking / drafted / planned / open and its cluster
GET /api/v1/memory?site=&status=allreadthe facts the writer may state, each with its source page and quote
GET /api/v1/search-console/importsreadyour imports with their windows
GET /api/v1/tasks?status=open|done|allreadthe task list with evidence
POST /api/v1/tasks, POST /api/v1/tasks/:id/statusresearchadds tasks ({ title, detail?, site?, link? } or { tasks: [...] }), marks one open or done

A client in twenty lines

const BASE = 'https://rankwhy.com/api/v1';
const KEY = process.env.RANKWHY_KEY;

async function rankwhy(path, init = {}) {
  const res = await fetch(BASE + path, { ...init, headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json', ...(init.headers || {}) } });
  if (res.status === 429) { await new Promise(r => setTimeout(r, 60_000)); return rankwhy(path, init); }
  const body = await res.json();
  if (!res.ok) throw new Error(body.error);
  return body;
}

const { data: sites } = await rankwhy('/sites');
const { data: guard } = await rankwhy('/guard?site=' + encodeURIComponent(sites[0].site));
for (const f of guard.findings) console.log(f.page, f.kind, f.evidence);
await rankwhy('/tasks', { method: 'POST', body: JSON.stringify({ title: 'Fix the title on /pricing', detail: guard.findings[0]?.evidence, site: sites[0].site }) });

Webhooks: the calendar sends every finished article to your endpoint, signed; see publishing.

Related