The REST API for reading your graph, score and recommendations — and for starting scans. JSON responses, authenticated with API keys.
Base URL
All endpoints live under the /v1 prefix and are served over HTTPS only.
Base URL
https://api.graphorank.com
Authentication
Generate a key from the app's API & MCP page. Keys are prefixedgr_, shown in full only once at creation, and stored hashed. Send the key in the X-Api-Key header on every request.
Keys carry scopes: read (always granted) covers every GET endpoint, while write is required to create sites, start scans and manage schedules. The app's own session uses a JWT in the Authorization: Bearer header instead — API keys are for programmatic access.
Shell
# Create a key in the app under API & MCP — keys start with "gr_"
export GRAPHORANK_API_KEY="gr_..."
curl https://api.graphorank.com/v1/sites \
-H "X-Api-Key: $GRAPHORANK_API_KEY"
A site is a root domain in your workspace. Add it, prove you own it, then scan it. Ownership uses a well-known file or a meta tag — the exact token snippet lives in Getting started.
Fetch a single site. The response has the same shape as a list item of GET /v1/sites.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
POST/v1/sites/{site_id}/verify
Run the ownership check with the method you picked. The response always includes your site token, so you can call this endpoint once to retrieve it before publishing the file or meta tag.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
methodbody · stringrequiredVerification method: "file" (well-known file) or "meta" (homepage meta tag).
{
"verified": true,
"method": "file",
"token": "9Kd2mQx7Ln4pTv8waZrGQg",
"detail": "token found at /.well-known/graphorank-verify.txt"
}
Scans
A scan runs the full pipeline: crawl, semantic analysis, graph build, scoring. Its status moves through queued → crawling → embedding → scoring → done (or failed, with an error code). Scans count toward your plan's monthly quota.
POST/v1/sites/{site_id}/scans
Start an on-demand scan. Requires the write scope. Returns 202 with the queued scan; when the monthly quota is exhausted you get 402 quota_exceeded.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
render_modebody · stringOptional: "http", "js" or "auto". Omit to use the default — auto enables JS rendering only when the site needs it.
The complete node/edge graph of a completed scan, in the same format the app's interactive view consumes. Large graphs are served in cursor pages of 1,000 elements (nodes first, then edges): keep requesting with the returned next_cursor until it comes back null. The meta object is repeated on every page.
GET/v1/scans/{scan_id}/graph
Nodes carry the role (pillar | cluster | hub | money | orphan | noindex), structural and semantic cluster ids, PageRank, in/out degree, click depth and indexability. Edges are internal links.
PARAMETERTYPEDESCRIPTION
scan_idpath · uuidrequiredScan identifier.
cursorquery · integerCursor returned by the previous page. Defaults to 0 (first page).
GraphRank is a 0–100 benchmark of how visible a site is to generative engines. The endpoint returns it together with the four area scores shown in the app — structural, topical, GEO and technical — plus the detail object that powers the in-app explanations. The methodology behind the number is proprietary and applied identically to every site.
GET/v1/scans/{scan_id}/score
GraphRank and the four area scores for a completed scan.
Prioritized fixes generated from the scan, each with a severity (P0 blocking, P1 important, P2 nice-to-have), localized messages and a meta object with the affected URL plus extra context.
GET/v1/scans/{scan_id}/recommendations
List the scan's recommendations, most severe first.
PARAMETERTYPEDESCRIPTION
scan_idpath · uuidrequiredScan identifier.
severityquery · stringOptional filter: "P0", "P1" or "P2".
[
{
"id": "b7e3a9c1-5d2f-4e8b-a1c6-3f9d7e2b8a54",
"page_id": "9c2b1e07-4f6a-4d3e-b8a1-7c5e9f2d1b36",
"type": "orphan_page",
"severity": "P0",
"message_it": "Pagina orfana: nessun link interno la raggiunge. Collegala dalla sezione pertinente.",
"message_en": "Orphan page: no internal link reaches it and crawlers struggle to find it. Link it from the relevant section.",
"meta": { "url": "https://rovere-arredamenti.com/blog/cura-del-rovere" }
}
]
History & diff
Track how the score evolves across scans, and diff two of them to see exactly what changed — pages added and removed, orphans, indexability.
GET/v1/sites/{site_id}/history
GraphRank time series for the site, one point per completed scan, ordered by timestamp.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
fromquery · date-timeOnly points at or after this ISO 8601 timestamp.
toquery · date-timeOnly points at or before this ISO 8601 timestamp.
Compare two scans of the same site. Without parameters it compares the two most recent completed scans. score_delta and sub_deltas are null when either scan has no score.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
from_scanquery · uuidBaseline scan. Defaults to the second most recent completed scan.
to_scanquery · uuidTarget scan. Defaults to the most recent completed scan.
One recurring scan per site, with an email report on completion. Available on Pro and Agency plans — on lower tiers these endpoints return 402 quota_exceeded with an upgrade hint.
POST/v1/sites/{site_id}/schedule
Create or update the site's schedule (upsert — one per site). Requires the write scope.
PARAMETERTYPEDESCRIPTION
site_idpath · uuidrequiredSite identifier.
freqbody · stringrequired"weekly" or "monthly".
daybody · integerrequiredWeekly: 0–6 with Monday = 0. Monthly: 1–28.
timebody · stringrequired24-hour "HH:MM", UTC.
recipientsbody · string[]requiredUp to 10 email addresses that receive the report.
Workspace-level keys for programmatic access, prefixed gr_ and stored hashed. The plaintext key is returned only once, in the creation response — store it in a secret manager. Scopes: read (always included) covers every GET endpoint; write is required for anything that mutates state.
GET/v1/api-keys
List the workspace's keys. Secrets are never returned after creation.
Revoke a key. It stops working immediately. Returns 204 No Content.
PARAMETERTYPEDESCRIPTION
key_idpath · uuidrequiredKey identifier.
Rate limits & errors
Two token buckets protect the API: one per client IP (applied before authentication) and one per workspace (applied after). When you hit a limit the response is 429 with a Retry-After header telling you how many seconds to wait.
Errors use the application/problem+json format — { type, title, status, detail, code }. Request-validation errors (422) return the standard detail array pointing at the offending fields.
402 · problem+json
{
"type": "about:blank",
"title": "Quota Exceeded",
"status": 402,
"detail": "monthly scan quota reached (6/6): upgrade your plan or wait for the next period",
"code": "quota_exceeded"
}
STATUSCODEWHEN
401unauthorizedMissing or invalid credentials (X-Api-Key or Bearer JWT).
402quota_exceededPlan quota reached, or the feature needs a higher tier. Upgrade or wait for the next period.
403forbiddenThe key's scopes don't allow this call (e.g. write is required).
404not_foundThe resource doesn't exist in your workspace — you never see other tenants' data.
422validation_errorMalformed body or parameters; the response lists the offending fields.
429rate_limitedToo many requests — honor the Retry-After header (seconds).
503service_unavailableA downstream dependency is unavailable. Retry later.