API

Endpoint Reference

Every operation in the VitalSentinel public API, grouped by module, with the scope each one requires. 336 operations across 25 groups.

View as Markdown

336 operations across 25 groups. Every path below is relative to https://app.vitalsentinel.com/api/public/v1.

This page is a map. The OpenAPI document is the contract, and it carries the request and response schemas, the query parameters, and the per-operation notes that are too long to fit in a table.

Read the conventions first. Pagination, time ranges, and idempotency apply across the whole surface and are not repeated per endpoint.

Meta

No scope required. Both cost 0 credits.

MethodPathDescription
GET/healthService health. Unauthenticated.
GET/meDescribe the calling credential, its scopes, and its effective scopes

Crawler

No scope required. Unauthenticated. Costs 0 credits.

MethodPathDescription
GET/crawlerFacts about the VitalSentinel crawler, including its IP addresses and check rates

Use it to keep your firewall allowlist up to date. See Monitoring IPs.

Workspaces and domains

Read-only. Creating or editing a workspace or a domain is a dashboard-only operation.

MethodPathScopeDescription
GET/workspacesread:workspacesList accessible workspaces
GET/workspaces/{workspace_id}read:workspacesGet a workspace
GET/domainsread:domainsList domains
GET/domains/{domain_id}read:domainsGet a domain
GET/domains/{domain_id}/limitsread:domainsGet plan limits and usage
GET/domains/{domain_id}/verificationread:domains, read:pages, or read:site_healthGet the domain verification status. Read-only: the API cannot start a verification

/workspaces and /domains return the page envelope but always as a single page today, and both cost 0 credits.

/workspaces reports no retention figure, because retention is not a per-workspace number: every plan keeps a given kind of data for the same length of time. To size a query window, use the fixed windows in Retention - 16 months for RUM and CrUX, 12 for Synthetic, Uptime, robots.txt and Indexing, 10 years for Search Console and Web Analytics.

Domain overview and health

The two cross-module summaries. Start here rather than fanning out across every module.

MethodPathScopeDescription
GET/domains/{domain_id}/overviewread:overviewCross-module summary with period comparison
GET/domains/{domain_id}/healthread:domainsCross-module health snapshot

/overview covers eleven modules, including Page Monitoring, Site Health Monitoring and Sitemap Monitoring. /health covers nine modules, including Site Health Monitoring. A module block is null when the module is not set up for the domain. null does not mean healthy. Both use a fixed 28-day window that is not configurable. The differences that decide which you want:

/overview/health
Scope requiredread:overviewread:domains
WindowLast 28 daysLast 28 complete UTC days versus the 28 before
ComparisonThree modules: CrUX, Search Console, Web AnalyticsEvery configured module
Freshness controlNone. Always cached, up to an hour oldfreshness=cached (default) or freshness=live
Reports its own stalenessNoYes, meta.cache_age_seconds

/health is the one to reach for during an incident. Pass freshness=live to bypass the cache and recompute every module now. It is slower, and cache_age_seconds comes back as 0 so you know you got a fresh answer.

On the default freshness=cached, check meta.cache_age_seconds before trusting uptime.is_up. A snapshot up to an hour old is fine for a dashboard and wrong for "is the site up right now".

/overview has no freshness lever at all, so do not use it for a time-sensitive question. Use /health?freshness=live, or /uptime/status, which is never cached.

URL Overview

MethodPathScopeDescription
GET/domains/{domain_id}/url-overviewAny module read: scope, or read:overviewEverything VitalSentinel knows about one URL, right now. Pass the full URL in url. 5 credits

The response has one section for each module: crawl data, Search Console, URL inspection, server logs, sitemap, robots.txt, Web Analytics, RUM, CrUX, Synthetic Monitoring, uptime and open alerts. Each section shows the latest state, not the history.

Each section has a status. not_in_scope means that the credential has no scope for that module. not_connected means that the module is not available for the domain. timeout means that the section was too slow, and the other sections still come back.

A cached answer costs 0. A credential that holds only read:overview pays 0 and gets only the url section.

Credits

MethodPathScopeDescription
GET/creditsnoneWorkspace credit balance and your own cap
GET/credits/logread:credits for OAuth; admin or owner role alwaysThis cycle's spending, request by request
GET/credits/workspacesnoneOne balance per accessible workspace, each with its own cycle

All three cost 0 credits. /credits and /credits/log take an optional workspace_id; /credits/workspaces takes no parameters, because it already covers every workspace the credential can reach. A request is charged to the workspace whose data it read, so a connection covering several workspaces has a separate balance and a separate log for each. Omit the parameter for the connection's default workspace, which is the only one for an API key.

Workspaces do not share a billing cycle, so the balances /credits/workspaces returns each carry their own cycle_start and cycle_end. Adding their used figures together blends different date ranges into a number that describes no real cycle.

See API credits.

Uptime

Scope: read:uptime. There is no write:uptime; uptime configuration is dashboard-only.

MethodPathDescription
GET/domains/{domain_id}/uptime/statusCurrent uptime status. Never cached, so this is the right call for "is the site up right now"
GET/domains/{domain_id}/uptime/availabilityUptime availability percentage
GET/domains/{domain_id}/uptime/timelineUptime check timeline, bucketed
GET/domains/{domain_id}/uptime/incidentsDowntime incidents
GET/domains/{domain_id}/uptime/response-timesDNS, connect, TLS, and total response-time breakdown
GET/domains/{domain_id}/uptime/slow-checksSlow but successful checks
GET/domains/{domain_id}/uptime/stats-extraResponse-time percentiles, MTTR, and slow-check count
GET/domains/{domain_id}/uptime/configGet uptime monitoring configuration

SSL

Scope: read:ssl.

MethodPathDescription
GET/domains/{domain_id}/ssl/summarySSL status summary
GET/domains/{domain_id}/ssl/latestLatest SSL certificate
GET/domains/{domain_id}/sslSSL certificate chain detail
GET/domains/{domain_id}/ssl/historySSL certificate history
GET/domains/{domain_id}/ssl/eventsSSL certificate change events
GET/domains/{domain_id}/ssl/domain-expirationDomain registration expiration

CrUX

Scopes: read:crux, write:crux.

MethodPathScopeDescription
GET/domains/{domain_id}/crux/overviewread:cruxLatest CrUX overview
GET/domains/{domain_id}/crux/timelineread:cruxCrUX metrics timeline
GET/domains/{domain_id}/crux/compareread:cruxCompare metrics between two periods
GET/domains/{domain_id}/crux/trends/{metric_name}read:cruxTrend for one metric
GET/domains/{domain_id}/crux/histogram/{metric_name}read:cruxDistribution histogram for one metric
GET/domains/{domain_id}/crux/urlsread:cruxList monitored URLs
GET/domains/{domain_id}/crux/urls/{url_id}read:cruxGet a monitored URL
POST/domains/{domain_id}/crux/urls/bulkwrite:cruxAdd multiple URLs. 25 credits
POST/domains/{domain_id}/crux/urls/bulk-deletewrite:cruxRemove multiple URLs
DELETE/domains/{domain_id}/crux/urls/{url_id}write:cruxRemove a URL

There is no way to trigger a CrUX refresh through the API. Collection draws from a shared platform-wide key pool, so a scripted refresh loop would degrade collection for every other customer.

Synthetic Monitoring

Scopes: read:synthetic, write:synthetic. There is no run:synthetic: a scripted "run it now" against the schedule is an unbounded test bill for data that was coming anyway.

MethodPathScopeDescription
GET/domains/{domain_id}/synthetic/overviewread:syntheticOverview
GET/domains/{domain_id}/synthetic/timelineread:syntheticTest timeline
GET/domains/{domain_id}/synthetic/trendsread:syntheticMetric trends over time
GET/domains/{domain_id}/synthetic/compareread:syntheticCompare performance between two periods
GET/domains/{domain_id}/synthetic/tests/{test_id}read:syntheticFull results for one test
GET/domains/{domain_id}/synthetic/opportunitiesread:syntheticRecurring Lighthouse opportunities, aggregated across recent runs
GET/domains/{domain_id}/synthetic/urlsread:syntheticList monitored URLs
GET/domains/{domain_id}/synthetic/urls/{url_id}read:syntheticGet a monitored URL
GET/domains/{domain_id}/synthetic/urls/{url_id}/locationsread:syntheticConfigured locations for a URL
GET/domains/{domain_id}/synthetic/locationsread:syntheticAvailable testing locations
GET/domains/{domain_id}/synthetic/locations-with-dataread:syntheticLocations with collected data
GET/domains/{domain_id}/synthetic/location-limitsread:syntheticLocation limits for this workspace
POST/domains/{domain_id}/synthetic/urls/bulkwrite:syntheticAdd multiple URLs. 25 credits
POST/domains/{domain_id}/synthetic/urls/bulk-deletewrite:syntheticRemove multiple URLs
POST/domains/{domain_id}/synthetic/urls/bulk-frequencywrite:syntheticUpdate frequency for multiple URLs
PUT/domains/{domain_id}/synthetic/urls/{url_id}/frequencywrite:syntheticUpdate the frequency for one URL
PUT/domains/{domain_id}/synthetic/urls/{url_id}/locationswrite:syntheticSet the locations for one URL
DELETE/domains/{domain_id}/synthetic/urls/{url_id}write:syntheticRemove a URL

RUM

Scope: read:rum. Read-only, and redacted more strictly than the dashboard.

MethodPathDescription
GET/domains/{domain_id}/rum/overviewRUM overview
GET/domains/{domain_id}/rum/has-dataWhether this domain has any RUM data at all
GET/workspaces/{workspace_id}/rum/has-dataWhether each domain in a workspace has any RUM data
GET/domains/{domain_id}/rum/vitalsCore Web Vitals, by device type
GET/domains/{domain_id}/rum/vitals/timelineCore Web Vitals over time
GET/domains/{domain_id}/rum/vitals/distribution-timelineGood, needs-improvement, and poor split over time
GET/domains/{domain_id}/rum/vitals/lcp/subpartsLCP timing breakdown
GET/domains/{domain_id}/rum/vitals/lcp/subparts/timelineLCP timing breakdown, daily
GET/domains/{domain_id}/rum/vitals/lcp/element-typesLCP breakdown by element type
GET/domains/{domain_id}/rum/vitals/lcp/element-types/timelineLCP element types, daily
GET/domains/{domain_id}/rum/vitals/lcp/resourcesTop LCP resources
GET/domains/{domain_id}/rum/vitals/inp/subparts/timelineINP timing breakdown, daily
GET/domains/{domain_id}/rum/vitals/inp/script-domainsTop INP script sources
GET/domains/{domain_id}/rum/vitals/ttfb/subparts/timelineTTFB timing breakdown, daily. Carries a sixth, nullable field, avg_waiting_time_ms
GET/domains/{domain_id}/rum/pagesPage performance breakdown
GET/domains/{domain_id}/rum/pageviewsAggregated page views
GET/domains/{domain_id}/rum/eventsIndividual RUM events
GET/domains/{domain_id}/rum/errorsError counts by type
GET/domains/{domain_id}/rum/errors/groupsDistinct error kinds
GET/domains/{domain_id}/rum/errors/detailsDetailed error records with stack traces
GET/domains/{domain_id}/rum/engagementUser engagement metrics
GET/domains/{domain_id}/rum/engagement/correlationPerformance versus engagement correlation histogram
GET/domains/{domain_id}/rum/geographicGeographic distribution of RUM metrics

/workspaces/{workspace_id}/rum/has-data is the one workspace-scoped route in this group, so it takes a workspace_id rather than a domain_id. It reports every domain in the workspace in one call, which is how to find out which of your sites are reporting RUM at all without asking domain by domain.

/rum/vitals/ttfb/subparts/timeline gained a sixth field, avg_waiting_time_ms. It is the span from navigation start to the DNS lookup - redirects, the previous page's unload, service-worker start-up and the cache lookup - and it is the phase the breakdown never measured. With it, avg_waiting_time_ms + avg_dns_time_ms + avg_connection_time_ms + avg_request_time_ms equals TTFB exactly. The TLS and response fields are context, not summands: TLS is already inside connection setup, and the response is the body download that begins after the first byte.

The field is nullable, and null means "not measured", never zero - a real reading of zero is possible, so the two cannot share a value. Do not coalesce it to 0, which turns an unmeasured phase into a published reading of zero.

The RUM days parameters cap at 496, which covers the full 16-month window RUM is kept for. A larger value returns 422 rather than an empty series.

Web Analytics

Scopes: read:analytics, write:analytics, run:analytics.

MethodPathScopeDescription
GET/domains/{domain_id}/analytics/overviewread:analyticsTraffic overview
GET/domains/{domain_id}/analytics/timelineread:analyticsVisitors and pageviews timeline
GET/domains/{domain_id}/analytics/realtimeread:analyticsLive activity
GET/domains/{domain_id}/analytics/pagesread:analyticsTop, entry, or exit pages
GET/domains/{domain_id}/analytics/authorsread:analyticsReading numbers per article author
GET/domains/{domain_id}/analytics/authors/articlesread:analyticsThe articles one author is credited on
GET/domains/{domain_id}/analytics/sourcesread:analyticsTraffic source breakdown
GET/domains/{domain_id}/analytics/devicesread:analyticsDevice, browser, and OS breakdown
GET/domains/{domain_id}/analytics/geographicread:analyticsGeographic breakdown
GET/domains/{domain_id}/analytics/eventsread:analyticsCustom events
GET/domains/{domain_id}/analytics/searchread:analyticsSite search queries
GET/domains/{domain_id}/analytics/outboundread:analyticsOutbound link clicks
GET/domains/{domain_id}/analytics/downloadsread:analyticsFile download clicks
GET/domains/{domain_id}/analytics/ecommerce/overviewread:analyticsEcommerce overview
GET/domains/{domain_id}/analytics/ecommerce/productsread:analyticsEcommerce products. 25 credits, never discounted
GET/domains/{domain_id}/analytics/configread:analyticsGet analytics configuration
PUT/domains/{domain_id}/analytics/configwrite:analyticsUpdate analytics configuration
GET/domains/{domain_id}/analytics/funnelsread:analyticsList funnels
GET/domains/{domain_id}/analytics/funnels/{funnel_id}read:analyticsGet a funnel
POST/domains/{domain_id}/analytics/funnelswrite:analyticsCreate a funnel
PUT/domains/{domain_id}/analytics/funnels/{funnel_id}write:analyticsUpdate a funnel
DELETE/domains/{domain_id}/analytics/funnels/{funnel_id}write:analyticsDelete a funnel
GET/domains/{domain_id}/analytics/experimentsread:analyticsList experiments
GET/domains/{domain_id}/analytics/experiments/{experiment_id}read:analyticsGet an experiment
GET/domains/{domain_id}/analytics/experiments/{experiment_id}/evaluationsread:analyticsList evaluations
GET/domains/{domain_id}/analytics/experiments/{experiment_id}/evaluations/latestread:analyticsLatest evaluation
POST/domains/{domain_id}/analytics/experimentswrite:analyticsCreate an experiment
PUT/domains/{domain_id}/analytics/experiments/{experiment_id}write:analyticsUpdate an experiment
DELETE/domains/{domain_id}/analytics/experiments/{experiment_id}write:analyticsDelete an experiment
POST/domains/{domain_id}/analytics/experiments/{experiment_id}/evaluaterun:analyticsEvaluate an experiment. 25 credits, needs Idempotency-Key
GET/domains/{domain_id}/analytics/reports/_registeredread:analyticsList registered report keys
GET/domains/{domain_id}/analytics/reports/_summaryread:analyticsLatest run per registered report
GET/domains/{domain_id}/analytics/reports/{key}/latestread:analyticsLatest completed run for a report
GET/domains/{domain_id}/analytics/reports/runs/{run_id}read:analyticsGet a report run
GET/domains/{domain_id}/analytics/reports/runs/{run_id}/rowsread:analyticsPaginated slice of a run's rows
POST/domains/{domain_id}/analytics/reports/{report_key}/runrun:analyticsRun an on-demand report. 25 credits, needs Idempotency-Key

Google Search Console

Scopes: read:gsc, write:gsc, run:gsc.

MethodPathScopeDescription
GET/domains/{domain_id}/gsc/overviewread:gscOverview statistics
GET/domains/{domain_id}/gsc/performanceread:gscPerformance time series. 25 credits, never discounted
GET/domains/{domain_id}/gsc/queriesread:gscQuery-level performance
GET/domains/{domain_id}/gsc/pagesread:gscPage-level performance
GET/domains/{domain_id}/gsc/countriesread:gscPerformance by country
GET/domains/{domain_id}/gsc/devicesread:gscPerformance by device
GET/domains/{domain_id}/gsc/search-appearanceread:gscPerformance by search appearance type
GET/domains/{domain_id}/gsc/ctr-benchmarkread:gscActual versus expected CTR across this domain's own position distribution
GET/domains/{domain_id}/gsc/new-rankingsread:gscQueries or pages new to this domain's rankings
GET/domains/{domain_id}/gsc/known-eventsread:gscKnown events annotated on this domain's traffic
GET/domains/{domain_id}/gsc/brand-patternsread:gscBrand-query patterns
GET/domains/{domain_id}/gsc/url-patternsread:gscURL-template pattern overrides
GET/domains/{domain_id}/gsc/locale-configread:gscLocale-detection configuration
GET/domains/{domain_id}/gsc/experimentsread:gscList experiments
GET/domains/{domain_id}/gsc/experiments/{experiment_id}/evaluations/latestread:gscLatest evaluation
POST/domains/{domain_id}/gsc/experimentswrite:gscCreate an A/B experiment
PUT/domains/{domain_id}/gsc/experiments/{experiment_id}write:gscUpdate an experiment
DELETE/domains/{domain_id}/gsc/experiments/{experiment_id}write:gscDelete an experiment
POST/domains/{domain_id}/gsc/experiments/{experiment_id}/evaluaterun:gscEvaluate an experiment. 25 credits, needs Idempotency-Key
GET/domains/{domain_id}/gsc/reports/_registeredread:gscReports available to run
GET/domains/{domain_id}/gsc/reports/_summaryread:gscReports hub summary
GET/domains/{domain_id}/gsc/reports/{report_key}/latestread:gscLatest completed run for a report
GET/domains/{domain_id}/gsc/reports/runs/{run_id}read:gscGet a report run
GET/domains/{domain_id}/gsc/reports/runs/{run_id}/rowsread:gscPaginated slice of a run's rows
POST/domains/{domain_id}/gsc/reports/{report_key}/runrun:gscRun a report. 25 credits, needs Idempotency-Key

Search Console data hangs off the domain its property is linked to. Connecting or disconnecting a Google account is a dashboard-only operation.

Indexing Monitoring

Scopes: read:indexing, write:indexing.

MethodPathScopeDescription
GET/domains/{domain_id}/indexing/timelineread:indexingCoverage-state timeline
GET/domains/{domain_id}/indexing/issue-summaryread:indexingAggregate issue counts
GET/domains/{domain_id}/indexing/inspectionsread:indexingURL Inspection results
GET/domains/{domain_id}/indexing/url-historyread:indexingEvery past inspection for one URL
GET/domains/{domain_id}/indexing/state-changesread:indexingRecent per-URL coverage-state transitions
GET/domains/{domain_id}/indexing/sitemapsread:indexingSearch Console sitemap coverage stats
GET/domains/{domain_id}/indexing/diagnosticsread:indexingCollection diagnostics
GET/domains/{domain_id}/indexing/groupsread:indexingList URL groups
GET/domains/{domain_id}/indexing/priority-urlsread:indexingList priority-queue URLs
GET/domains/{domain_id}/indexing/propertiesread:indexingList enrolled Search Console properties
POST/domains/{domain_id}/indexing/groupswrite:indexingCreate a URL group
PATCH/domains/{domain_id}/indexing/groups/{group_id}write:indexingUpdate a URL group
DELETE/domains/{domain_id}/indexing/groups/{group_id}write:indexingDelete a URL group
POST/domains/{domain_id}/indexing/priority-urlswrite:indexingAdd a URL to the priority inspection queue
DELETE/domains/{domain_id}/indexing/priority-urls/{priority_url_id}write:indexingRemove a URL from the priority queue
POST/domains/{domain_id}/indexing/properties/{property_id}write:indexingEnroll a property. 25 credits
DELETE/domains/{domain_id}/indexing/properties/{property_id}write:indexingRemove a property
GET/domains/{domain_id}/indexing/log-stale-crawlread:indexingStale-crawl analysis from observed Googlebot fetches. Needs Server Log Monitoring
GET/domains/{domain_id}/indexing/log-coverage-checkread:indexingSelf-check: crawls Search Console reports the log collector never saw. Needs Server Log Monitoring
GET/domains/{domain_id}/indexing/inspection-candidatesread:indexingWhere to spend today's inspection quota, ranked by observed log activity. Needs Server Log Monitoring
GET/domains/{domain_id}/indexing/log-crawled-not-indexedread:indexing"Crawled - currently not indexed", re-read against real crawl frequency. Needs Server Log Monitoring
GET/domains/{domain_id}/indexing/log-index-latencyread:indexingTime from a page's first observed crawl to it being indexed. Needs Server Log Monitoring

Robots.txt Monitoring

Scopes: read:robots, write:robots. There is no run:robots; robots.txt is fetched on a schedule.

MethodPathScopeDescription
GET/domains/{domain_id}/robots/latestread:robotsLatest fetched robots.txt
GET/domains/{domain_id}/robots/healthread:robotsFetch health
GET/domains/{domain_id}/robots/timelineread:robotsFetched versions
GET/domains/{domain_id}/robots/changesread:robotsList changes
GET/domains/{domain_id}/robots/diff-impactsread:robotsPer-change before and after impact
GET/domains/{domain_id}/robots/crawler-accessread:robotsPer-crawler allow and disallow matrix
GET/domains/{domain_id}/robots/ai-botsread:robotsAI-bot governance view
GET/domains/{domain_id}/robots/test-urlread:robotsTest whether a URL is allowed for one crawler
POST/domains/{domain_id}/robots/test-urls/queryread:robotsTest a batch of URLs. Read-only POST
POST/domains/{domain_id}/robots/simulate/queryread:robotsSimulate a candidate robots.txt. Read-only POST
GET/domains/{domain_id}/robots/overlapping-rulesread:robotsOverlapping rules in the stored file
POST/domains/{domain_id}/robots/overlapping-rules/queryread:robotsOverlapping rules in a candidate file. Read-only POST
GET/domains/{domain_id}/robots/sitemap-conflictsread:robotsSitemap URLs blocked by robots.txt
GET/domains/{domain_id}/robots/sitemap-conflicts/summaryread:robotsConflict summary
GET/domains/{domain_id}/robots/top-blockedread:robotsHigh-traffic URLs blocked by robots.txt
GET/domains/{domain_id}/robots/validation/historyread:robotsValidation results
GET/domains/{domain_id}/robots/annotationsread:robotsList change annotations
POST/domains/{domain_id}/robots/annotationswrite:robotsAdd a note to a change
PATCH/domains/{domain_id}/robots/annotations/{annotation_id}write:robotsUpdate an annotation
DELETE/domains/{domain_id}/robots/annotations/{annotation_id}write:robotsDelete an annotation
POST/domains/{domain_id}/robots/sitemap-conflicts/recomputewrite:robotsRecompute the sitemap conflict check. Needs Idempotency-Key. Priced as an ordinary write

write:robots edits VitalSentinel's own annotations on a change, and triggers the sitemap-conflict recompute. It does not, and cannot, edit the robots.txt file on your site.

The recompute re-diffs the sitemap URLs VitalSentinel has already stored against the current robots.txt. It returns straight away and does the work in the background, so poll /robots/sitemap-conflicts/summary for the result. It does not fetch a fresh sitemap, so it clears the staleness caused by the check lagging behind a stored sitemap, but not the staleness caused by an old sitemap check. Sitemap Monitoring reads the sitemaps again every 24 hours, and that clears it.

Sitemap Monitoring

Scope: read:sitemap. Read-only. VitalSentinel checks the sitemaps of each domain automatically every 24 hours. See Sitemap Monitoring.

MethodPathDescription
GET/domains/{domain_id}/sitemap/summarySitemap Monitoring summary
GET/domains/{domain_id}/sitemap/statsCheck statistics: the URLs in the sitemaps now, the first and the latest check, and when the next check is due
GET/domains/{domain_id}/sitemap/checksList sitemap checks
GET/domains/{domain_id}/sitemap/checks/{seq}Get one sitemap check
GET/domains/{domain_id}/sitemap/compareCompare two sitemap checks. 5 credits
GET/domains/{domain_id}/sitemap/changesList the URL changes between checks. 5 credits
GET/domains/{domain_id}/sitemap/urlsExport every discovered sitemap URL. Use in_sitemap to get current, removed, or all (default) URLs. 5 credits
GET/domains/{domain_id}/sitemap/urls/historyThe history of one sitemap URL
GET/domains/{domain_id}/sitemap/filesList the sitemap files and the result of each download
GET/domains/{domain_id}/sitemap/files/{file_id}Get one sitemap file
GET/domains/{domain_id}/sitemap/hostsList the hosts in the sitemap URLs, up to 200
GET/domains/{domain_id}/sitemap/sourcesWhere each sitemap was found
GET/domains/{domain_id}/sitemap/configScan configuration
GET/domains/{domain_id}/sitemap/rate-limitWhether a scan can be started

Some fields need a second scope. Search Console figures, such as clicks on a removed URL, need read:gsc. Google indexing figures on a sitemap file need read:indexing. Without the second scope, these fields are null.

To find sitemap URLs blocked by robots.txt, either read the stored result at /robots/sitemap-conflicts, refreshing it first with POST /robots/sitemap-conflicts/recompute if it is stale, or export the full URL list here plus the latest robots.txt and compute the intersection yourself.

Site Health Monitoring

Scopes: read:site_health, write:site_health. There is no run:site_health, because your plan sets how often pages are checked. Every write: operation needs the owner or admin role. See Site Health Monitoring.

MethodPathScopeDescription
GET/domains/{domain_id}/site-healthread:site_healthSite Health Monitoring overview
GET/domains/{domain_id}/site-health/issuesread:site_healthList issues
GET/domains/{domain_id}/site-health/issues/{issue_id}read:site_healthGet one issue with its evidence. 5 credits
GET/domains/{domain_id}/site-health/issues/{issue_id}/affected-urlsread:site_healthList the pages an issue affects
POST/domains/{domain_id}/site-health/issues/{issue_id}/{action}write:site_healthAct on an issue: acknowledge (Mark as seen), ignore (Snooze…), accept-baseline (This is normal…) or reopen
GET/domains/{domain_id}/site-health/ignore-rulesread:site_healthList ignore rules
POST/domains/{domain_id}/site-health/ignore-ruleswrite:site_healthAdd an ignore rule
DELETE/domains/{domain_id}/site-health/ignore-rules/{rule_id}write:site_healthRemove an ignore rule
GET/domains/{domain_id}/site-health/sampleread:site_healthThe pages that Site Health Monitoring checks
GET/domains/{domain_id}/site-health/sample/urlsread:site_healthList the checked URLs
GET/domains/{domain_id}/site-health/pinsread:site_healthList pinned URLs
POST/domains/{domain_id}/site-health/pinswrite:site_healthPin a URL
DELETE/domains/{domain_id}/site-health/pins/{pin_id}write:site_healthUnpin a URL
GET/domains/{domain_id}/site-health/settingsread:site_healthGet the settings
PATCH/domains/{domain_id}/site-health/settingswrite:site_healthChange the settings
GET/domains/{domain_id}/site-health/availabilityread:site_healthWhether the crawler can reach the site
GET/domains/{domain_id}/site-health/deploysread:site_healthDetected site changes (deploys)
GET/domains/{domain_id}/site-health/ai-readabilityread:site_healthWhat AI crawlers can read. Server log figures need read:logs

Page Monitoring

Scopes: read:pages, write:pages, run:pages. Every write: and run: operation needs the owner or admin role. See Page Monitoring.

MethodPathScopeDescription
GET/domains/{domain_id}/page-monitoringread:pagesPage Monitoring overview
GET/domains/{domain_id}/page-monitoring/watchesread:pagesList watched pages
GET/domains/{domain_id}/page-monitoring/watches/migration-summaryread:pagesMigration check summary
POST/domains/{domain_id}/page-monitoring/watcheswrite:pagesWatch one page
POST/domains/{domain_id}/page-monitoring/watches/bulkwrite:pagesWatch up to 500 pages, within your plan limit
GET/domains/{domain_id}/page-monitoring/watches/{watch_id}read:pagesGet one watched page
PATCH/domains/{domain_id}/page-monitoring/watches/{watch_id}write:pagesChange a watched page
DELETE/domains/{domain_id}/page-monitoring/watches/{watch_id}write:pagesStop watching a page
POST/domains/{domain_id}/page-monitoring/watches/{watch_id}/resumewrite:pagesResume a page that was paused for the plan limit
POST/domains/{domain_id}/page-monitoring/watches/{watch_id}/checkrun:pagesCheck a page now. 25 credits, needs Idempotency-Key
GET/domains/{domain_id}/page-monitoring/jobs/{job_id}read:pages or run:pagesGet the status of a check
GET/domains/{domain_id}/page-monitoring/watches/{watch_id}/checksread:pagesList the checks of a watched page
GET/domains/{domain_id}/page-monitoring/watches/{watch_id}/compareread:pagesCompare two checks of a watched page. 5 credits
GET/domains/{domain_id}/page-monitoring/watches/{watch_id}/impactread:pagesSearch impact of the changes on a watched page. Search Console figures need read:gsc and Googlebot figures need read:logs
GET/domains/{domain_id}/page-monitoring/watches/{watch_id}/changes/{change_id}read:pagesGet one change of a watched page
GET/domains/{domain_id}/page-monitoring/changesread:pagesThe change feed
GET/domains/{domain_id}/page-monitoring/change-kindsread:pagesList the kinds of change
GET/domains/{domain_id}/page-monitoring/limitsread:pagesGet the plan limits
GET/domains/{domain_id}/page-monitoring/issuesread:pagesList issues
GET/domains/{domain_id}/page-monitoring/issues/{issue_id}read:pagesGet one issue with its evidence. 5 credits
POST/domains/{domain_id}/page-monitoring/issues/{issue_id}/{action}write:pagesAct on an issue: acknowledge (Mark as seen), ignore (Snooze…), accept-baseline (This is normal…) or reopen
GET/domains/{domain_id}/page-monitoring/custom-elementsread:pagesList custom elements
POST/domains/{domain_id}/page-monitoring/custom-elements/testread:pagesTest a selector against a stored version. Read-only POST. 5 credits
POST/domains/{domain_id}/page-monitoring/custom-elementswrite:pagesAdd a custom element
PATCH/domains/{domain_id}/page-monitoring/custom-elements/{element_id}write:pagesChange a custom element
DELETE/domains/{domain_id}/page-monitoring/custom-elements/{element_id}write:pagesDelete a custom element
GET/domains/{domain_id}/page-monitoring/ignore-rulesread:pagesList ignore rules
POST/domains/{domain_id}/page-monitoring/ignore-ruleswrite:pagesAdd an ignore rule
DELETE/domains/{domain_id}/page-monitoring/ignore-rules/{rule_id}write:pagesRemove an ignore rule

A check started through the API uses the same hourly allowance as the Check now button in the dashboard. When the allowance is used, the API refuses the check with a rate-limit error. A retry with the same Idempotency-Key returns the same check and costs 0.

Stored page versions

Scope: read:pages or read:site_health. Site Health Monitoring and Page Monitoring share the stored versions of a page, so either scope reads them. A 403 lists both scopes and shows that one of them is enough.

MethodPathDescription
GET/domains/{domain_id}/crawl/pagesA crawled page, found by its URL. Pass the URL in url
GET/domains/{domain_id}/crawl/pages/{url_id}A crawled page, found by its url_id
GET/domains/{domain_id}/crawl/pages/{url_id}/versionsList the stored versions of a page
GET/domains/{domain_id}/crawl/pages/{url_id}/versions/{version_id}Get one stored version
GET/domains/{domain_id}/crawl/pages/{url_id}/versions/{version_id}/htmlThe stored HTML of a version, as text. 5 credits for the first part. More parts of the same version within 10 minutes cost 0
GET/domains/{domain_id}/crawl/pages/{url_id}/diffCompare two versions of a page. 5 credits

The stored HTML comes from your site. The API returns it as text, never as a web page.

Server Log Monitoring

Scope: read:logs. Read-only: there is no write:logs or run:logs, so the API cannot connect a log source or start a collection run.

Every route costs 5 credits on the heavy-query rate-limit bucket, except /logs/sources and /logs/exclusions, which cost 1. The API never returns a visitor IP address: unverified and spoofed traffic is grouped per network (ASN). See Server Log Monitoring for what each report means.

MethodPathDescription
GET/domains/{domain_id}/logs/overviewHits overview: timeline by bot category, status mix, totals
GET/domains/{domain_id}/logs/botsPer-bot activity table
GET/domains/{domain_id}/logs/categoriesBot activity grouped by category
GET/domains/{domain_id}/logs/sectionsCrawl activity grouped by site section
GET/domains/{domain_id}/logs/pagesCrawled pages
GET/domains/{domain_id}/logs/pages/{url_id}/detailOne page's crawl detail
GET/domains/{domain_id}/logs/crawled-pagesCrawled pages: one row per URL, up to 12 months
GET/domains/{domain_id}/logs/urls-to-fixEvery URL crawlers got an error or a redirect for, one row per URL
GET/domains/{domain_id}/logs/status-codesBot-by-status-code matrix and the error explorer
GET/domains/{domain_id}/logs/status-timelineStatus codes over time, one series per exact code
GET/domains/{domain_id}/logs/exploreRequest-level drill-down: which crawler and which pages got a given status
GET/domains/{domain_id}/logs/crawl-budgetCrawl budget: waste, per-section spend, waste composition, top and long-tail URL split
GET/domains/{domain_id}/logs/crawl-mechanics/duplicate-variantsBudget spent fetching the same page under different URLs
GET/domains/{domain_id}/logs/crawl-mechanics/depthHow many folders deep verified Googlebot's crawl reaches
GET/domains/{domain_id}/logs/treeSite-structure crawl map: known vs crawled URLs, folder by folder
GET/domains/{domain_id}/logs/ai-crawlersAI crawler activity, licensing split and robots.txt compliance
GET/domains/{domain_id}/logs/ai-crawlers/coverage-gapPages verified Googlebot crawled that no AI crawler has fetched
GET/domains/{domain_id}/logs/securitySpoofed bot identities, ASN clusters and scanner activity
GET/domains/{domain_id}/logs/sourcesLog source configuration and health. 1 credit
GET/domains/{domain_id}/logs/exclusionsExcluded traffic: what the collection policy did not keep, and why. 1 credit
GET/domains/{domain_id}/logs/search-console/funnelCrawl-to-click funnel per URL
GET/domains/{domain_id}/logs/search-console/crawl-roiShare of crawl spent per section against share of clicks
GET/domains/{domain_id}/logs/search-console/stale-money-pagesImpressions behind pages Google stopped re-crawling
GET/domains/{domain_id}/logs/search-console/ctr-vs-crawlCTR underperformance crossed with stale crawl
GET/domains/{domain_id}/logs/search-console/impression-collapsePages whose impressions fell away as crawl errors appeared
GET/domains/{domain_id}/logs/search-console/discovery-latencyTime from first Googlebot crawl to first search impression
GET/domains/{domain_id}/logs/search-console/crawl-frequency-positionWhether the most-crawled sections are the best-ranking ones
GET/domains/{domain_id}/logs/search-console/algorithm-eventsKnown search algorithm events over this site's crawl timeline
GET/domains/{domain_id}/logs/web-analytics/bot-shareBot share of total traffic, with Web Analytics as the human denominator
GET/domains/{domain_id}/logs/web-analytics/crawl-visit-gapPages people visit that Googlebot hasn't crawled
GET/domains/{domain_id}/logs/web-analytics/ai-funnelAI visibility funnel: crawled, cited and visited
GET/domains/{domain_id}/logs/rum/ttfb-bot-vs-humanBot TTFB against human TTFB for the same URL
GET/domains/{domain_id}/logs/rum/cwv-crawl-priorityPoor Core Web Vitals on heavily-crawled pages
GET/domains/{domain_id}/logs/sitemap/orphan-pagesCrawled by Google, missing from your sitemap
GET/domains/{domain_id}/logs/sitemap/uncrawled-urlsSitemap URLs Googlebot has not crawled recently
GET/domains/{domain_id}/logs/sitemap/crawl-liftWhether being in the sitemap increases Googlebot crawl frequency
GET/domains/{domain_id}/logs/sitemap/new-urls-foundNew URLs Googlebot found this week
GET/domains/{domain_id}/logs/robots/behaviour-deltaWhat crawlers did before and after a robots.txt change
GET/domains/{domain_id}/logs/robots/complianceHow closely each bot honors this site's robots.txt
GET/domains/{domain_id}/logs/robots/ineffective-disallowDisallow rules verified crawlers are still ignoring
GET/domains/{domain_id}/logs/robots/ai-policy-realityWhat this site tells AI bots vs what they actually did
GET/domains/{domain_id}/logs/robots/fetch-healthNon-200 responses to a bot's request for /robots.txt
GET/domains/{domain_id}/logs/uptime/seo-costSearch and AI crawler errors during downtime
GET/domains/{domain_id}/logs/uptime/crawl-drop-attributionCrawl decline explained by an incident
GET/domains/{domain_id}/logs/uptime/certificate-eventsCrawler behavior around certificate renewals and expiries
GET/domains/{domain_id}/logs/indexing/crawl-drop-leading-indicatorCrawl volume next to indexing health, week by week

The cross-module routes return a source-coverage block, so a figure that a missing source (Search Console, Web Analytics, RUM or a sitemap) cannot establish comes back as unknown rather than zero.

Alerts

Scopes: read:alerts, write:alerts. Members can create and edit alert rules, because a rule belongs to whoever created it.

Alert rules also cover Page Monitoring, Site Health Monitoring and Sitemap Monitoring. See Alert types.

MethodPathScopeDescription
GET/alerts/metricsread:alertsAvailable alert metrics. Costs 0 credits
GET/alerts/rulesread:alertsAccount-wide: rules on every accessible domain. Optional workspace_id, module, and enabled filters. Costs 0 credits
GET/alerts/historyread:alertsAccount-wide: fired alerts on every accessible domain, newest first. Optional workspace_id and domain_id filters. Costs 0 credits
GET/domains/{domain_id}/alerts/rulesread:alertsPer domain: rules on this one domain
GET/domains/{domain_id}/alerts/rules/{rule_id}read:alertsGet a rule
GET/domains/{domain_id}/alerts/historyread:alertsPer domain: fired alerts on this one domain
POST/domains/{domain_id}/alerts/ruleswrite:alertsCreate a rule
PUT/domains/{domain_id}/alerts/rules/{rule_id}write:alertsUpdate a rule
DELETE/domains/{domain_id}/alerts/rules/{rule_id}write:alertsDelete a rule

The account-wide /alerts/rules and /alerts/history answer "what do I have set up" and "what has fired lately" across every workspace the credential can reach, without looping over /domains first. Every row names its own domain and workspace, so nothing has to be correlated against a second call. Both cost 0 credits, because a call that reads every accessible workspace has no single workspace to charge. Narrowing one with workspace_id or domain_id does not change that, since those are query filters rather than part of the path.

Read /alerts/metrics before building a rule. It is free and it is what tells you which metric and comparison combinations are valid.

There is no endpoint to test-fire a rule. The dashboard does not expose one either.

Notifications

Scopes: read:notifications, write:notifications. Scoped to the calling user, not to the workspace. Members keep write access here, because these are personal preferences.

Because they are user-scoped rather than workspace-scoped, every route in this group costs 0 credits. The one exception is GET /notifications/{notification_id}/trend, which recomputes a series from live data and costs 1.

MethodPathScopeDescription
GET/notificationsread:notificationsList notifications
GET/notifications/unread-countread:notificationsUnread count
GET/notifications/statsread:notificationsNotification statistics
GET/notifications/{notification_id}/trendread:notificationsLive trend behind a fired alert
GET/notifications/preferencesread:notificationsGet preferences
GET/notifications/domain-subscriptionsread:notificationsPer-domain email subscriptions
POST/notifications/readwrite:notificationsMark notifications as read
POST/notifications/{notification_id}/readwrite:notificationsMark one as read
POST/notifications/{notification_id}/unreadwrite:notificationsMark one as unread
DELETE/notifications/{notification_id}write:notificationsDelete a notification
PUT/notifications/preferenceswrite:notificationsUpdate preferences
PUT/notifications/domain-subscriptionswrite:notificationsUpdate a per-domain subscription

Fired alerts arrive as notifications carrying the alert rule and alert history identifiers, so this is where you watch for an alert firing.

Reports

Scopes: read:reports, write:reports, run:reports.

MethodPathScopeDescription
GET/domains/reports/sections-catalogread:reportsAvailable sections and widgets. Costs 0 credits
GET/domains/reports/default-configread:reportsDefault sections_config for a new template. Costs 0 credits
GET/domains/{domain_id}/reports/templatesread:reportsList templates
GET/domains/{domain_id}/reports/templates/{template_id}read:reportsGet a template
POST/domains/{domain_id}/reports/data/{template_id}read:reportsCollect report data as JSON. Read-only POST
POST/domains/{domain_id}/reports/templateswrite:reportsCreate a template
PUT/domains/{domain_id}/reports/templates/{template_id}write:reportsUpdate a template
POST/domains/{domain_id}/reports/templates/{template_id}/duplicatewrite:reportsDuplicate a template
DELETE/domains/{domain_id}/reports/templates/{template_id}write:reportsDelete a template
POST/domains/{domain_id}/reports/{template_id}/generaterun:reportsGenerate a PDF. 25 credits, needs Idempotency-Key
GET/domains/{domain_id}/reports/jobs/{job_id}run:reportsCheck a PDF job. Priced as a read
GET/domains/{domain_id}/reports/jobs/{job_id}/downloadrun:reportsDownload a completed PDF. Priced as a read

PDF generation is asynchronous. POST .../generate returns a job identifier; poll /reports/jobs/{job_id} until it completes, then download. Polling is priced as an ordinary read, so watching a report never costs more than starting one.

If you want the numbers rather than a PDF, use POST /reports/data/{template_id}. It returns the same content as JSON, needs only read:reports, and costs a read rather than 25 credits.

OAuth

The authorization server. See Authentication for the full flow.

MethodPathDescription
POST/oauth/registerRegister a client (RFC 7591)
GET/oauth/authorizeStart an authorization request
GET/oauth/authorize/requestResolve an authorization request handle
POST/oauth/authorize/consentRecord a consent decision
POST/oauth/tokenExchange an authorization code or refresh token
POST/oauth/revokeRevoke a token (RFC 7009)

Two discovery documents sit at the site root rather than under the API prefix:

GET https://app.vitalsentinel.com/.well-known/oauth-authorization-server
GET https://app.vitalsentinel.com/.well-known/oauth-protected-resource

On this page

VitalSentinel

Catch issues before they cost you

Track SEO, performance, and uptime in one place and get alerted the moment something breaks – hours before it hits your traffic.

  • Free plan for 1 domain
  • Set up in minutes
  • No credit card required