RankRight API
A REST API built for AI agents and integrations — reads, org-scoped RPCs,
background jobs and report files. Base URL:
https://app.rankright.dev/api/v1
Try it now — public sandbox
A shared, read-only, rate-limited key over fictional data
(Harbor Light Home Services, client_id 108). Every read RPC, the MCP
server and these docs work with it; writes and jobs answer 403 with a hint.
Authorization: Bearer rrk_u154NZ009Kk_dbtPPuXeCpYbEZQgX6gziL-i7uZIN8k
curl -X POST https://app.rankright.dev/api/v1/rpc/get_aeo_summary -H 'Authorization: Bearer rrk_u154NZ009Kk_dbtPPuXeCpYbEZQgX6gziL-i7uZIN8k' -H 'Content-Type: application/json' -d '{"client_id": 108}'
Data is reset periodically. Sign up for a key with the write scope to use your own clients.
Authentication
Every request carries an API key in the Authorization
header:
Authorization: Bearer rrk_<your-key>
Keys are issued by the platform administrator — contact
[email protected]
to request one for your organization. Keys are org-scoped:
every call is confined and metered to your organization, and the RPC
registry is deny-by-default — methods that haven't been vetted for
external use return 403. Only the sha256 of your key is
stored server-side; treat the plaintext like a password. Lost keys
can't be recovered, only revoked and re-minted.
Requests are rate-limited per key (per-minute window; over-limit calls
get 429 with a Retry-After header). Write
access depends on your key's scopes (read,
write, jobs).
Endpoints
| Method & path | What it does |
|---|---|
GET /api/v1/health |
Liveness probe — no auth required. Returns status + row counts. |
POST /api/v1/rpc/<method> |
Call a vetted RPC method. JSON body = keyword arguments.
Your org id is injected server-side — you never pass it, and you
can't read or write another org's data. Unknown / unvetted
methods return 403. |
GET /api/v1/db/<table> |
Generic filtered read of an allowed table. Filter with
?where_<column>=value query params; org
scoping is applied automatically. |
POST /api/v1/jobs |
Enqueue a background job (audits, rebuilds, reports…). Returns
{ job_id, status_url }. Requires the
jobs scope. |
GET /api/v1/jobs/<id> |
Poll job status + progress + result payload. |
POST /api/v1/jobs/<id>/cancel |
Cancel a queued or running job. |
GET /api/v1/files/<path> |
Download generated artifacts (reports, snapshots) referenced by job results. |
MCP server
Connect an agent directly (Model Context Protocol, Streamable HTTP, same bearer key — same scope,
org isolation and rate limits as the REST API). Tools: every org-scoped RPC (clients, AI Visibility,
branding) plus list_rpcs / describe_rpc / call_rpc for the rest.
Resources: these docs. Prompts: the workflows.
# Claude Code
claude mcp add --transport http rankright https://app.rankright.dev/api/v1/mcp \
--header "Authorization: Bearer rrk_..."
# Generic MCP client config
{"mcpServers": {"rankright": {"type": "http", "url": "https://app.rankright.dev/api/v1/mcp",
"headers": {"Authorization": "Bearer rrk_..."}}}}
SDKs & stability
Python: pip install rankright — or straight from here,
pip install https://app.rankright.dev/sdk/rankright-python.zip (source, MIT).
Any RPC as a method, jobs with wait, exports, OAuth login for CLIs/agents, webhook verification, retries, idempotency keys.
TypeScript / others: generate from https://app.rankright.dev/api/v1/openapi.json.
from rankright import Client
rr = Client(api_key="rrk_...") # or access_token="rro_..." from OAuth
rr.get_aeo_summary(client_id=12)
job = rr.exports.run(); rr.exports.download(job, "export.zip")
Versioning: the API is path-versioned (/api/v1, echoed in X-RankRight-API-Version).
Additive changes ship any time and are listed in the changelog; breaking changes only in
/api/v2 with 12 months of overlap; a documented method is retired only after 60 days' notice (owner email, the
api.deprecation webhook, Deprecation/Sunset/Link headers on every call until then).
OAuth 2.0 for apps & MCP clients
Third-party applications should not hold long-lived keys. RankRight is an OAuth 2.0 authorization server:
authorization code + PKCE (S256) only, dynamic client registration (RFC 7591), discovery at
https://app.rankright.dev/.well-known/oauth-authorization-server and
https://app.rankright.dev/.well-known/oauth-protected-resource/api/v1/mcp. Access tokens (rro_…)
live one hour; refresh tokens rotate and slide for 30 days. Scopes read, write,
jobs, offline_access, capped by the approving member's role. Members manage grants under
Account → Connected apps.
# MCP clients need nothing but the URL — they discover OAuth and open the consent page
claude mcp add --transport http rankright https://app.rankright.dev/api/v1/mcp
# Any client: register once, then the standard code + PKCE flow
curl -X POST https://app.rankright.dev/oauth/register -H "Content-Type: application/json" \
-d '{"client_name": "My agent", "redirect_uris": ["https://myapp.example/callback"]}'
# → open https://app.rankright.dev/oauth/authorize?response_type=code&client_id=…&redirect_uri=…&scope=read+write+offline_access
# &code_challenge=…&code_challenge_method=S256&state=…
# → POST https://app.rankright.dev/oauth/token grant_type=authorization_code&code=…&code_verifier=…&client_id=…&redirect_uri=…
# → Authorization: Bearer rro_… on /api/v1/* and the MCP server
Security & policies
Encryption, tenant isolation, key scopes, retention, US data residency, incident handling and vulnerability
disclosure are documented on the security page
(machine-readable contact at /.well-known/security.txt). See also the
Privacy Policy (sub-processors, Google Limited Use) and
Terms of Service (API deprecation notice, data export).
Single sign-on
Interactive login supports OpenID Connect (authorization code + PKCE, scopes
openid email profile). Configured here:
Google.
- Bring your own IdP: Self-serve: an organization owner adds any OIDC issuer (Google Workspace, Microsoft Entra, Okta, OneLogin, JumpCloud, Vendasta) under Account → Single sign-on — issuer URL, client id/secret, allowed email domains, default role for new staff. Register the redirect_uri above with the IdP. Staff then sign in at /login/sso with their work email; unknown staff on an allowed domain are provisioned into that organization. RPCs: list/add/update/delete_org_sso_provider. Redirect URI:
https://app.rankright.dev/auth/oidc/<provider>/callback - Verification: id_token signature via the provider JWKS; issuer, audience, expiry and nonce checked; state is single-use with a 10-minute TTL; only verified emails are accepted.
- Accounts: The verified email is matched to an existing RankRight user (any org). An SSO sign-in stands in for the TOTP second factor. Unknown emails are provisioned as owner of a new organization only when the provider has allow_signup, the email domain is in its allowed_domains, or public signup is open; otherwise the user is told to ask an owner for an invite.
- SAML: SAML 2.0 supported, self-serve per organization (Account → Single sign-on → SAML): SP-initiated, HTTP-Redirect AuthnRequest, HTTP-POST Response; signed Responses or Assertions verified against the IdP certificate; Conditions, Audience, Recipient and InResponseTo checked; encrypted assertions not supported. Give the IdP the SP metadata URL https://app.rankright.dev/saml/<provider key>/metadata (ACS https://app.rankright.dev/saml/<provider key>/acs). Staff sign in at https://app.rankright.dev/login/sso.
- API & MCP: SSO governs interactive sign-in only; API and MCP access always use rrk_ bearer keys.
Webhooks
Skip polling: register an https endpoint and receive a signed POST when something happens.
register_webhook(url, events) (owner) returns the signing secret once; manage with
list_webhooks, update_webhook, rotate_webhook_secret,
delete_webhook, test_webhook, list_webhook_deliveries,
redeliver_webhook — or on the account page.
| Event | When |
|---|---|
job.completed / job.failed / job.cancelled | A background job reached a terminal state (kind, client_id, error, result summary, status_url). |
aeo.capture.ingested | An AI-engine answer was captured and analyzed (engine, month, scorecard, new / carried / resolved counts). |
aeo.report.saved | A monthly AI Visibility report was filed. |
aeo.item.status_changed / action_item.status_changed | A tracker / action item changed status. |
ping | Sent by test_webhook. |
POST <your url>
Content-Type: application/json
X-RankRight-Event: job.completed
X-RankRight-Delivery: 8123
X-RankRight-Timestamp: 1788650000
X-RankRight-Signature: t=1788650000,v1=<hex HMAC-SHA256(secret, "1788650000." + body)>
{"id": 8123, "event": "job.completed", "created_at": "…", "org_id": 7, "client_id": 42, "data": {…}}
Respond 2xx within 10 s. Failures retry with exponential backoff (1, 2, 4 … 64 min, 8 attempts); a hook is disabled after 100 consecutive failures. Reject deliveries whose timestamp is more than 5 minutes old. URLs must be https and publicly routable.
Machine-readable docs & workflows
Everything on this page, generated from the live registries (cannot drift):
GET https://app.rankright.dev/llms.txt— orientation for AI agents (public)GET https://app.rankright.dev/developers.md— full guide: conventions, workflows, every RPC with params and summary (public;/llms-full.txtis the same text)GET https://app.rankright.dev/api/v1/openapi.json— OpenAPI 3.1, operations tagged by domain (ai-visibility,clients,search-console, …), workflows underx-workflows(public)GET https://app.rankright.dev/api/v1/capabilities— the same inventory as JSON (auth)
Export everything in three calls
POST /api/v1/jobs {"kind": "export_org"}(owner key; a service account addsorg_id)- poll
GET /api/v1/jobs/<id>— or take thejob.completedwebhook GET /api/v1/exports/<org_id>/<filename>— every table as JSON + CSV, filed reports, a manifest; kept 7 days
AI Visibility (AEO) in six calls
Does ChatGPT / Claude / Gemini name and cite a client for buyer questions? All org-scoped by client_id.
generate_aeo_questions(client_id)— question set from the client's services + locationsset_aeo_cadence(client_id, samples_per_month=1, engines=['claude','chatgpt-web'])— enrol; the daily sweep queues runsget_aeo_summary(client_id)— presence / named-first per service, open tasks, queueget_aeo_items(client_id, status='open')— the action list (tier A/B website, C Google Business / directories, X market-driven)update_aeo_item_status(item_id, 'done', client_id=…)— as work completesaeo_report_html(client_id, month)— white-label monthly report (update_organization_brandingsets name / logo / accent)
Quick start
# Liveness
curl https://app.rankright.dev/api/v1/health
# List your clients
curl -X POST https://app.rankright.dev/api/v1/rpc/get_all_clients \
-H "Authorization: Bearer rrk_..." \
-H "Content-Type: application/json" -d '{}'
# Enqueue a job, then poll it
curl -X POST https://app.rankright.dev/api/v1/jobs \
-H "Authorization: Bearer rrk_..." \
-H "Content-Type: application/json" \
-d '{"kind": "strategist", "client_id": 123}'
curl https://app.rankright.dev/api/v1/jobs/456 \
-H "Authorization: Bearer rrk_..."
Errors are JSON: {"error": "..."} with conventional HTTP
status codes (401 bad/revoked key, 403
not permitted, 404 not found / not yours,
429 rate-limited, 503 writes disabled).