Developer reference · 7 July 2026
API & data reference
Every figure on Visa Atlas — fees, cost-to-complete models, salary floors, processing times, policy changes, the Canada Express Entry draw history, country comparisons, citation packs, the AI citation benchmark and the source-transparency benchmark — is also available as plain JSON, free to reuse under CC BY 4.0. This page documents every endpoint, every field, and shows a real example for each. The machine-readable OpenAPI 3.1 contract is available at /api/openapi.json.
At a glance
- Base URL
- https://visaatlas.org/api/public
- Format
- JSON (UTF-8)
- Auth
- None — fully open
- Method
- GET; route finder also accepts POST
- License
- CC BY 4.0
- Rate limits
- None stated — static, be reasonable
Endpoints
- Catalog
/api/public - Indexable page manifest
/api/public/indexable-pages - Public site search index
/api/public/search-index - Visa routes
/api/public/visas - Destinations
/api/public/destinations - Policy updates
/api/public/policy-updates - Policy claims
/api/public/policy-claims - Citation packs
/api/public/citation-packs - Verified answer capsules
/api/public/answer-capsules - AI citation benchmark
/api/public/citation-benchmark - AI retrieval task index
/api/public/ai-retrieval-task-index - AI retrieval readiness scorecard
/api/public/ai-retrieval-readiness - AI answer accuracy audit protocol
/api/public/ai-answer-accuracy-audit - Source transparency benchmark
/api/public/source-transparency-benchmark - SEO/GEO content opportunities
/api/public/content-opportunities - Competitor query battlecards
/api/public/competitor-query-battlecards - Battlecard search experiments
/api/public/battlecard-search-experiments - SERP and AI answer-surface snapshot protocol
/api/public/serp-answer-surface-snapshots - Quarterly market-share evidence summary
/api/public/quarterly-market-share-summary - Publisher and AI-citation kits
/api/public/publisher-citation-kits - Authority distribution plan
/api/public/authority-distribution-plan - Embeddable widget catalog
/api/public/widgets - External repository mirror manifest
/api/public/external-repository-mirrors - Knowledge-graph entity seeding manifest
/api/public/knowledge-graph-entities - Expert reviewer entity program
/api/public/expert-reviewer-entities - reviewedBy schema rollout controls
/api/public/reviewedby-schema-rollout - High-risk page review acquisition controls
/api/public/high-risk-page-review-acquisition - P0 reviewed page refresh controls
/api/public/p0-reviewed-page-refresh - Calculator verdict contexts
/api/public/calculator-verdict-contexts - Route finder
/api/public/route-finder - SEO/GEO visibility metrics
/api/public/visibility-metrics - SEO/GEO traffic forecast
/api/public/traffic-forecast - Technical SEO/GEO controls
/api/public/technical-seo-controls - Topical authority internal-link map
/api/public/topical-authority-map - SEO/GEO audit evidence pack
/api/public/seo-geo-audit-evidence - SEO/GEO execution readiness scorecard
/api/public/execution-readiness - SEO/GEO market-share capture plan
/api/public/market-share-capture-plan - SEO/GEO production queue
/api/public/seo-geo-production-queue - SEO/GEO page action map
/api/public/seo-geo-page-action-map - Battlecard retrieval coverage matrix
/api/public/battlecard-retrieval-coverage - SEO/GEO dominance gap ledger
/api/public/seo-geo-dominance-gap-ledger - SEO/GEO measurement run queue
/api/public/seo-geo-measurement-run-queue - SEO/GEO reviewer evidence bridge
/api/public/seo-geo-reviewer-evidence-bridge - SEO/GEO external evidence bridge
/api/public/seo-geo-external-evidence-bridge - SEO/GEO private measurement bridge
/api/public/seo-geo-private-measurement-bridge - SEO/GEO release gate contract
/api/public/seo-geo-release-gate - Search demand action map
/api/public/search-demand-actions - Crawler and AI retrieval access audit
/api/public/crawler-access - Source freshness
/api/public/freshness - Processing-time planning reliability
/api/public/processing-reliability - Skilled-migration planning accessibility
/api/public/skilled-migration-accessibility - Country comparisons
/api/public/country-comparisons - Fees
/api/public/fees - Cost to complete
/api/public/cost-to-complete - Salary thresholds
/api/public/salary-thresholds - Processing times
/api/public/processing-times - Canada Express Entry categories
/api/public/express-entry-categories - Canada Express Entry draws
/api/public/express-entry-draws - Rules and threshold fact changes
/api/public/fact-changes - Monthly immigration figure changes
/api/public/monthly-figure-changes
Conventions
- Every response is JSON served over HTTPS as a static file — fast, cacheable, and stable between deploys.
- Dates are ISO 8601 (
YYYY-MM-DD). - Money is an exact figure in
amountLocalwith a separate ISO 4217currency. We do not convert currencies; anapproxUsdfield, where present, is a rounded comparison figure only. - Destination keys are lowercase and not always ISO-3166 — we use
uk(notgb). Treat them as opaque identifiers; the destinations endpoint lists them all. - Most records carry their own
sourceUrl/sourceNameand alastChecked,lastVerifiedorlastRevieweddate. Always defer to the linked official source. - No pagination — datasets are small and returned in full. Optional fields are simply absent when not applicable.
Returns object · 58 datasets described
A self-describing index of the public reference and figure datasets, plus a schema.org DataCatalog wrapper and Dataset block for each one (the same metadata search engines and dataset registries read). Start here to discover what is available programmatically.
Fields
| Field | Type | Description |
|---|---|---|
| datasets[] | array<object> | One entry per figure dataset. |
| datasets[].path | string | The endpoint path, e.g. "/api/public/fees". |
| datasets[].title | string | Human title of the dataset. |
| datasets[].description | string | What the dataset contains. |
| datasets[].recordCount | number | Number of top-level records in that endpoint. |
| datasets[].dateModified | string (ISO date) | Freshness date for the endpoint, derived from source review dates. |
| datasets[].category | string | "reference" for lookup tables or "figures" for numeric/source-derived datasets. |
| datasets[].humanPath | string? | Best human-facing page for this dataset, where one exists. |
| datasets[].apiDocsPath | string | Anchor in this API reference for fields and examples. |
| datasets[].keywords[] | array<string> | Dataset discovery keywords used in Dataset JSON-LD. |
| datasets[].license | string | Always "CC BY 4.0". |
| datasets[].attribution | string | The credit to use: "Visa Atlas". |
| datasets[].primarySourceNote | string | Reminder that every figure links its official source. |
| catalogJsonld | object | schema.org DataCatalog object tying every public dataset to the canonical /data catalog. |
| jsonld[] | array<object> | A schema.org Dataset object per dataset (name, description, license, creator, distribution; the Express Entry entries also carry dates + sourceOrganization). |
Example response
{
"datasets": [
{
"path": "/api/public/fees",
"title": "Visa and immigration fees",
"description": "Government-published fee breakdowns by destination and visa route…",
"recordCount": 37,
"dateModified": "2026-06-01",
"category": "figures",
"humanPath": "/fees",
"apiDocsPath": "/api#fees",
"keywords": ["visa fees", "government fees", "immigration costs"],
"license": "CC BY 4.0",
"attribution": "Visa Atlas",
"primarySourceNote": "Every figure links to its official government primary source…"
}
// …visas, destinations, policy-updates, salary-thresholds, processing-times, express-entry-draws
],
"catalogJsonld": {
"@context": "https://schema.org",
"@type": "DataCatalog",
"@id": "https://visaatlas.org/data#catalog",
"name": "Visa Atlas public immigration data catalog",
"url": "https://visaatlas.org/data",
"dataset": [
{ "@type": "Dataset", "@id": "https://visaatlas.org/api/public/fees#dataset" }
]
},
"jsonld": [
{
"@context": "https://schema.org",
"@type": "Dataset",
"name": "Visa and immigration fees",
"license": "https://creativecommons.org/licenses/by/4.0/",
"url": "https://visaatlas.org/api/public/fees",
"creator": { "@type": "Organization", "name": "Visa Atlas" }
}
// …
]
}Returns object · 7,379 URLs
Audit mirror of the XML sitemap. Use it to reconcile the public indexability surface by page cohort, priority, change frequency, freshness date and the public datasets that audit each cohort.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Manifest contract version. |
| datasetUrl | string (URL) | Canonical JSON endpoint for this manifest. |
| sitemapUrl | string (URL) | Canonical XML sitemap the rows mirror. |
| summary.totalPages | number | Number of URLs emitted by the sitemap builder. |
| summary.pagesWithLastModified | number | Rows carrying an explicit lastModified date. |
| summary.highPriorityPages | number | Rows with priority >= 0.8. |
| summary.cohorts[] | array<object> | Counts by page cohort, e.g. visa-route, country-comparison, research and open-data. |
| pages[] | array<object> | One row per sitemap URL. |
| pages[].url | string (URL) | Absolute canonical URL. |
| pages[].path | string | URL path for joins against route templates and crawl logs. |
| pages[].cohort | string | Indexability cohort assigned from the path pattern. |
| pages[].changeFrequency | string? | Sitemap changeFrequency value, where set. |
| pages[].priority | number? | Sitemap priority value, where set. |
| pages[].lastModified | string? | Sitemap lastModified date, normalized to YYYY-MM-DD. |
| pages[].sourceDatasets[] | array<string> | Public JSON datasets that best audit the page cohort. |
Example response
{
"name": "Visa Atlas indexable page manifest",
"datasetUrl": "https://visaatlas.org/api/public/indexable-pages",
"sitemapUrl": "https://visaatlas.org/sitemap.xml",
"count": 7379,
"summary": {
"totalPages": 7379,
"pagesWithLastModified": 7209,
"highPriorityPages": 1934,
"cohorts": [
{ "cohort": "country-comparison", "count": 3371 }
]
},
"pages": [
{
"url": "https://visaatlas.org/visas/uk/skilled-worker",
"path": "/visas/uk/skilled-worker",
"cohort": "visa-route",
"changeFrequency": "weekly",
"priority": 0.9,
"lastModified": "2026-04-18",
"sourceDatasets": ["/api/public/visas", "/api/public/destinations"]
}
]
}- This feed proves indexability intent. It does not replace a live crawl, Search Console coverage export or ranking measurement.
- Rows are generated from the same buildSitemapEntries() function used by /sitemap.xml, so drift between XML and JSON is auditable.
Returns object · 1,986 entries
Compact title, description, URL and keyword map for searchable Visa Atlas pages. Use it when an agent, integration or internal tool needs to find the best destination, visa, calculator, data page, research report, policy update, route guide, ranking or best-of guide without scraping the HTML search page.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Search-index contract version. |
| datasetUrl | string (URL) | Canonical JSON endpoint for this index. |
| humanUrl | string (URL) | Human search page backed by the same index builder. |
| summary.byKind | object | Counts by searchable kind: Visa, Destination, Nationality, Route, Guide, Ranking, Calculator, Data, Research and Policy. |
| sourceDatasets[] | array<string> | Public datasets that audit or explain the indexed URL set. |
| items[] | array<object> | One searchable item per public page or page family target. |
| items[].id | string | Stable search-row identifier. |
| items[].kind | string | Searchable item kind. |
| items[].title | string | Human-readable title. |
| items[].description | string | Short summary used by search and agent retrieval. |
| items[].path | string | Canonical path on visaatlas.org. |
| items[].url | string (URL) | Absolute canonical URL. |
| items[].keywords[] | array<string> | Compact search and retrieval tokens. |
| items[].sourceDatasets[] | array<string> | Public datasets that best audit the row. |
Example response
{
"name": "Visa Atlas public site search index",
"datasetUrl": "https://visaatlas.org/api/public/search-index",
"humanUrl": "https://visaatlas.org/search",
"count": 1986,
"summary": {
"byKind": {"Visa":1414,"Destination":233,"Nationality":42,"Route":17,"Guide":6,"Ranking":6,"Calculator":8,"Data":202,"Research":21,"Policy":37}
},
"items": [
{
"id": "visa-as-employment-based-residency-petition",
"kind": "Visa",
"title": "American Samoa (United States territory) - Employment-Based Residency Petition",
"path": "/visas/american-samoa/employment-based-residency-petition",
"sourceDatasets": ["/api/public/visas", "/api/public/destinations"]
}
]
}- This is a retrieval and navigation index, not a Search Console export or ranking signal.
- Use /api/public/indexable-pages when you need the complete sitemap-backed indexability manifest.
Returns array<object> · 1414 routes
Every visa route we cover, as a flat list. Each entry is a summary card — the full eligibility, pathway and FAQ content lives on the route page linked via the destination + slug.
Fields
| Field | Type | Description |
|---|---|---|
| destination | string | Destination key (lowercase, e.g. "uk", "ca", "de"). |
| slug | string | Route slug; combine with destination to build the page URL /visas/{destination}/{slug}. |
| name | string | Official route name. |
| category | string | Route family, e.g. "work-sponsored", "work-unsponsored", "study", "family", "investor", "digital-nomad". |
| summary | string | One-sentence description. |
| sponsorshipRequired | boolean | Whether an employer/sponsor is required. |
| leadsToSettlement | boolean | Whether the route is a recognised pathway to permanent residence. |
| typicalDuration | string | Initial grant length and extension/settlement note. |
| primarySource | object | Official source: { label, url, authority, lastVerified }. |
| lastReviewed | string (ISO date) | When we last reviewed this route. |
Example response
[
{
"destination": "uk",
"slug": "skilled-worker",
"name": "Skilled Worker visa",
"category": "work-sponsored",
"summary": "Work visa for non-UK workers with a job offer from a Home Office–licensed sponsor…",
"sponsorshipRequired": true,
"leadsToSettlement": true,
"typicalDuration": "Up to 5 years on initial grant, extendable; leads to settlement…",
"primarySource": {
"label": "GOV.UK — Skilled Worker visa",
"url": "https://www.gov.uk/skilled-worker-visa",
"authority": "UK Home Office",
"lastVerified": "2026-04-18"
},
"lastReviewed": "2026-04-18"
}
]Returns array<object> · 233 destinations
The countries we cover, with their official immigration portal and the bodies that regulate immigration advice there.
Fields
| Field | Type | Description |
|---|---|---|
| iso | string | Our internal destination key, lowercase. Note these are not always ISO-3166 (we use "uk", not "gb"). |
| slug | string | URL slug for /visas/{slug} and related pages. |
| name | string | Long official country name. |
| region | string | Region grouping, e.g. "europe", "north-america", "asia-pacific", "middle-east". |
| flag | string | Flag emoji. |
| govPortal | string (URL) | The official government immigration portal. |
| regulators[] | array<object> | Advice regulators: { name, abbreviation, url, scope }. |
Example response
[
{
"iso": "uk",
"slug": "uk",
"name": "United Kingdom of Great Britain and Northern Ireland",
"region": "europe",
"flag": "🇬🇧",
"govPortal": "https://www.gov.uk/browse/visas-immigration",
"regulators": [
{
"name": "Immigration Advice Authority",
"abbreviation": "IAA",
"url": "https://www.gov.uk/government/organisations/immigration-advice-authority",
"scope": "Regulates non-solicitor immigration advisers in the UK…"
}
]
}
]Returns array<object> · 37 updates
Dated immigration policy changes with atomic claims, affected route slugs, status, severity and the primary government source behind each update.
Fields
| Field | Type | Description |
|---|---|---|
| id | string | Stable update ID. |
| title | string | Human-readable headline. |
| date | string (ISO date) | Announcement or publication date. |
| effectiveDate | string (ISO date)? | Effective date when different from the announcement date. |
| destination | string | Destination key affected by the change. |
| summary | string | One-sentence summary. |
| claims[] | array<object> | Atomic factual claims: { statement }. |
| primarySource | object | Official source: { label, url, authority, lastVerified }. |
| affectedVisas[] | array<string>? | Visa slugs touched by the update. |
| severity | string | minor, material or significant. |
| status | string | announced, consulting, scheduled or in-force. |
| lastReviewed | string (ISO date) | Last editorial/source review date. |
Example response
[
{
"id": "uk-2024-04-skilled-worker-salary-rise",
"title": "UK raises Skilled Worker salary thresholds",
"date": "2024-04-04",
"effectiveDate": "2024-04-04",
"destination": "uk",
"summary": "The Home Office raised the Skilled Worker general salary threshold...",
"claims": [{ "statement": "General salary threshold raised to GBP 38,700 for new Skilled Worker applications." }],
"primarySource": {
"label": "UK - Statement of Changes HC 590 (March 2024)",
"url": "https://www.gov.uk/government/collections/immigration-rules-statement-of-changes",
"authority": "UK Home Office",
"lastVerified": "2026-06-01"
},
"affectedVisas": ["skilled-worker"],
"severity": "significant",
"status": "in-force",
"lastReviewed": "2026-06-01"
}
]Returns object · 115 claims
Claim-level feed for AI retrievers and auditors: each record is one atomic policy claim with a stable URL, parent update, affected routes and the supporting source behind the claim.
Fields
| Field | Type | Description |
|---|---|---|
| lastModified | string (ISO date) | Most recent policy-claim review date in the feed. |
| count | number | Number of claim records. |
| claims[] | array<object> | One atomic policy claim per row, newest updates first. |
| claims[].claimId | string | Stable ID in the form {policyUpdateId}#claim-{n}. |
| claims[].claimUrl | string | Canonical URL fragment for the visible claim card. |
| claims[].statement | string | The claim text, designed to be quoted with its source. |
| claims[].updateId | string | Parent policy update ID. |
| claims[].updateTitle | string | Parent policy update title. |
| claims[].updateUrl | string | Canonical parent policy update URL. |
| claims[].destinationIso | string | Destination affected by the policy update. |
| claims[].destinationName | string | Human-readable destination name. |
| claims[].date | string (ISO date) | Announcement or publication date of the parent update. |
| claims[].effectiveDate | string (ISO date)? | Effective date when known. |
| claims[].status | string | announced, consulting, scheduled or in-force. |
| claims[].severity | string | minor, material or significant. |
| claims[].affectedVisas[] | array<object> | Affected routes with slug, name and canonical URL. |
| claims[].source | object | Supporting source: { label, url, authority, lastVerified }. |
| claims[].lastReviewed | string (ISO date) | Last editorial/source review date. |
Example response
{
"lastModified": "2026-06-27",
"count": 115,
"claims": [
{
"claimId": "uk-2025-07-skilled-worker-reforms#claim-1",
"claimUrl": "https://visaatlas.org/policy-updates/uk-2025-07-skilled-worker-reforms#claim-1",
"statement": "The Skilled Worker general salary threshold rose to GBP 41,700.",
"updateId": "uk-2025-07-skilled-worker-reforms",
"destinationIso": "uk",
"destinationName": "United Kingdom of Great Britain and Northern Ireland",
"date": "2025-07-22",
"effectiveDate": "2025-07-22",
"status": "in-force",
"severity": "significant",
"affectedVisas": [{ "slug": "skilled-worker", "name": "Skilled Worker visa", "url": "https://visaatlas.org/visas/uk/skilled-worker" }],
"source": {
"label": "GOV.UK - Statement of changes to the Immigration Rules: HC 997",
"url": "https://www.gov.uk/government/publications/statement-of-changes-to-the-immigration-rules-hc-997-july-2025",
"authority": "UK Home Office",
"lastVerified": "2026-07-01"
},
"lastReviewed": "2026-07-01"
}
]
}- Use claimUrl when citing a single policy fact; use updateUrl when citing the whole policy update.
- The source object is the government source that supports the claim. Visa Atlas is the compiler, not the issuing authority.
Returns object · 162 packets
Compact, source-linked answer packets for AI retrievers, journalists, researchers and auditors. Each packet turns an existing verified cost model, calculator verdict context, Express Entry draw, best-guide, visa-route, page-level answer, fee answer, processing-time answer, salary-threshold answer, settlement answer, research report, policy claim or fact-change record into a citable answer with canonical page URL, dataset URL, source URLs, date modified, license and suggested citation.
Fields
| Field | Type | Description |
|---|---|---|
| lastModified | string (ISO date) | Freshest date modified across all packets. |
| count | number | Number of packets in the feed. |
| datasetUrl | string (URL) | Canonical JSON endpoint URL for the citation-pack dataset. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| legalNote | string | Reminder that the packet is compiled data, not legal advice. |
| packs[] | array<object> | Citation packets, grouped by kind in the human page. |
| packs[].id | string | Stable fragment ID for /citation-packs#{id}. |
| packs[].kind | string | cost-to-complete, calculator-verdict, express-entry, best-guide, visa-route, page-answer, fee, processing-time, salary-threshold, settlement, research-report, policy-claim or fact-change. |
| packs[].answer | string | Short answer designed to be quoted with its source chain. |
| packs[].canonicalPageUrl | string (URL) | Human page or claim anchor that provides context. |
| packs[].datasetUrl | string (URL) | Underlying source dataset behind the packet. |
| packs[].facts[] | array<object> | Structured facts: { label, value, note?, sourceUrls[] }. |
| packs[].sources[] | array<object> | Source records: { label, url, authority?, lastVerified? }. |
| packs[].suggestedCitation | string | Ready-to-copy citation for the packet. |
Example response
{
"lastModified": "2026-07-15",
"count": 162,
"datasetUrl": "https://visaatlas.org/api/public/citation-packs",
"license": "CC BY 4.0",
"attribution": "Visa Atlas",
"packs": [
{
"id": "express-entry-latest-draw",
"kind": "express-entry",
"title": "Latest Canada Express Entry draw",
"answer": "The latest tracked Canada Express Entry draw is round 426...",
"url": "https://visaatlas.org/citation-packs#express-entry-latest-draw",
"canonicalPageUrl": "https://visaatlas.org/research/canada-express-entry-draw-tracker",
"datasetUrl": "https://visaatlas.org/api/public/express-entry-draws",
"facts": [{ "label": "CRS cut-off", "value": "392", "sourceUrls": ["https://www.canada.ca/..."] }],
"sources": [{ "label": "IRCC - Express Entry rounds of invitations", "authority": "Immigration, Refugees and Citizenship Canada" }],
"suggestedCitation": "Visa Atlas, \"Latest Canada Express Entry draw\", ..."
},
{
"id": "calculator-verdict-canada-crs",
"kind": "calculator-verdict",
"title": "Canada CRS calculator verdict context",
"canonicalPageUrl": "https://visaatlas.org/calculators/canada-crs",
"datasetUrl": "https://visaatlas.org/api/public/calculator-verdict-contexts"
}
]
}- Use /citation-packs#{id} for a compact human citation anchor and canonicalPageUrl when more context is needed.
- Calculator-verdict citation packs are derived from /api/public/calculator-verdict-contexts and should keep the linked official source URLs with the calculator interpretation.
- Page-answer citation packs are derived from /api/public/answer-capsules and preserve the page-level verified answer as a citable packet.
- Strategic fee, processing-time, salary-threshold, settlement and visa-route citation packs are derived from /api/public/answer-capsules for SEO/GEO target pages.
- Citation packs are derived from existing verified datasets; do not treat them as a separate legal authority.
Returns object · 292 capsules
Question-answer records extracted from rendered Visa Atlas verified-answer blocks. Use this endpoint when you need the concise answer layer attached to source URLs, canonical pages, dataset URLs, review dates, license and legal-scope notes.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Dataset version date. |
| name | string | Human dataset name. |
| description | string | What the answer-capsule feed contains. |
| datasetUrl | string (URL) | Canonical JSON endpoint URL. |
| humanUrl | string (URL) | Crawlable human index for the same records. |
| count | number | Number of answer capsules. |
| lastModified | string (ISO date) | Freshest source review date across all capsules. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| legalNote | string | Reminder that capsules are compiled data, not legal advice. |
| methodology[] | array<string> | How the capsule feed is generated and limited. |
| summary.kinds[] | array<object> | Counts by capsule kind. |
| summary.sourceUrlCount | number | Unique source URL count. |
| summary.canonicalPageCount | number | Unique canonical page count. |
| capsules[] | array<object> | One source-linked short answer per rendered answer block. |
| capsules[].id | string | Stable fragment ID for /answer-capsules#{id}. |
| capsules[].kind | string | fee, processing-time, salary-threshold, cost-to-complete, calculator-verdict, express-entry, settlement, timeline, best-guide, topic-cluster, visa-route, page-answer or research-report. |
| capsules[].question | string | The question the answer block addresses. |
| capsules[].answer | string | Short answer designed for quotation with source chain attached. |
| capsules[].pagePath | string | Site-relative page path containing the answer block. |
| capsules[].canonicalPageUrl | string (URL) | Absolute canonical page URL. |
| capsules[].datasetUrls[] | array<string> | Supporting public JSON datasets or source index pages. |
| capsules[].sourceUrls[] | array<string> | Government or authoritative source URLs supporting the answer. |
| capsules[].sources[] | array<object> | Source objects: { label, url, authority?, lastVerified }. |
| capsules[].dateModified | string (ISO date) | Source review date for the capsule. |
| capsules[].renderedSelector | string | Rendered-page marker, currently "[data-verified-answer]". |
| capsules[].suggestedCitation | string | Ready-to-copy citation for the capsule. |
Example response
{
"version": "2026-07-04",
"name": "Verified answer capsules",
"datasetUrl": "https://visaatlas.org/api/public/answer-capsules",
"humanUrl": "https://visaatlas.org/answer-capsules",
"count": 292,
"lastModified": "2026-07-17",
"summary": {
"kinds": [{ "kind": "fee", "count": 37 }],
"sourceUrlCount": 1109,
"canonicalPageCount": 292
},
"capsules": [
{
"id": "fee-uk-skilled-worker",
"kind": "fee",
"question": "How much does the Skilled Worker visa cost in United Kingdom?",
"answer": "The UK Skilled Worker visa costs around GBP 3,950...",
"pagePath": "/fees/uk/skilled-worker",
"canonicalPageUrl": "https://visaatlas.org/fees/uk/skilled-worker",
"datasetUrls": ["https://visaatlas.org/api/public/fees"],
"sourceUrls": ["https://www.gov.uk/skilled-worker-visa/how-much-it-costs"],
"sources": [{ "label": "GOV.UK - Skilled Worker visa: how much it costs", "lastVerified": "2026-06-01" }],
"dateModified": "2026-06-01",
"renderedSelector": "[data-verified-answer]",
"suggestedCitation": "Visa Atlas, \"How much does the Skilled Worker visa cost in United Kingdom?\", ..."
}
]
}- Use /answer-capsules#{id} for the compact human anchor and canonicalPageUrl for the full page context.
- Answer capsules are derived from existing source-linked pages and datasets; do not treat them as a separate legal authority.
Returns object · 48 benchmark questions; 7 accuracy answer-key prompts
Fixed high-intent skilled-migration question basket used by the offline citation-share monitor. Each question includes the user prompt, priority, topic, target Visa Atlas pages and source datasets expected to support the answer.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Benchmark version date. |
| name | string | Human benchmark name. |
| description | string | What the benchmark measures. |
| domain | string | Brand domain the monitor detects in answer citations. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| count | number | Number of questions in the benchmark basket. |
| accuracyAnswerKey | object | Conservative machine-checkable answer key used by --grade mode. |
| accuracyAnswerKey.count | number | Number of benchmark prompts with accuracy keys. |
| accuracyAnswerKey.methodology[] | array<string> | Limits on automated grading and required human review. |
| accuracyAnswerKey.keys[] | array<object> | One answer-key row per machine-gradable benchmark prompt. |
| accuracyAnswerKey.keys[].expectedFacts[] | array<object> | Accepted current facts and whether each fact is required for a pass. |
| accuracyAnswerKey.keys[].staleOrWrongClaims[] | array<string> | Known stale or wrong values that should fail the row. |
| questions[] | array<object> | One benchmark prompt per row. |
| questions[].id | string | Stable prompt ID used in monitor logs. |
| questions[].destination | string | Country or route group the question targets. |
| questions[].topic | string | Intent bucket, e.g. salary-threshold, cost-to-complete or settlement. |
| questions[].priority | string | Benchmark priority: high, medium or low. |
| questions[].question | string | Exact prompt text sent to configured answer engines. |
| questions[].targetUrls[] | array<string> | Visa Atlas pages that should be cite-worthy for this prompt. |
| questions[].sourceDatasets[] | array<string> | Public JSON datasets that support the underlying facts. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas AI citation benchmark",
"domain": "visaatlas.org",
"license": "CC BY 4.0",
"attribution": "Visa Atlas",
"count": 48,
"accuracyAnswerKey": {
"version": "2026-07-02",
"count": 7,
"keys": [
{
"id": "de-blue-card-salary",
"expectedFacts": [{ "label": "2026 general EU Blue Card threshold", "required": true }],
"staleOrWrongClaims": ["EUR 48,300"]
}
]
},
"questions": [
{
"id": "de-blue-card-salary",
"destination": "Germany",
"topic": "salary-threshold",
"priority": "high",
"question": "What is the Germany EU Blue Card minimum salary threshold for 2026?",
"targetUrls": ["/salary-thresholds/germany", "/cost-to-complete/germany-eu-blue-card"],
"sourceDatasets": ["/api/public/salary-thresholds", "/api/public/cost-to-complete"]
}
]
}- The endpoint publishes benchmark prompts, target URLs and the conservative answer key; it does not store model responses or API keys.
- Use npm run kpi:citation-share to run the benchmark locally against configured answer engines.
- Use npm run kpi:citation-accuracy to run the same benchmark with conservative answer-key grading; partial or failed rows need human review.
Returns object · 48 retrieval tasks
Query-level retrieval contract derived from the fixed citation benchmark. Each task joins a high-intent immigration question to canonical pages, answer capsules, citation packs, calculator verdict contexts, SEO/GEO page actions, competitor battlecards, MCP tools, safe-answer rules and evidence gates.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Retrieval-index version date. |
| name | string | Human dataset name. |
| description | string | What the retrieval index covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the task index. |
| humanUrl | string | Crawlable report page explaining the index. |
| sourceDatasets[] | array<string> | Public datasets used to derive and audit task rows. |
| methodology.sourceOfTruth | string | How rows are generated from the fixed citation benchmark. |
| methodology.joinRules[] | array<string> | Exact join rules for answer capsules, citation packs, calculator contexts, page actions and battlecards. |
| methodology.retrievalStandard | string | How an AI retriever should use the row before composing an answer. |
| methodology.privateEvidencePolicy | string | Boundary for raw AI transcripts, GSC queries, SERP screenshots, analytics, referral logs and reviewer evidence. |
| summary.taskCount | number | Number of benchmark questions converted to retrieval tasks. |
| summary.rowsWithAnswerCapsules | number | Task rows with joined answer capsules. |
| summary.rowsWithCitationPacks | number | Task rows with joined citation packs. |
| summary.rowsWithCalculatorContexts | number | Task rows with joined calculator verdict contexts. |
| summary.rowsWithPageActions | number | Task rows with joined SEO/GEO page actions. |
| summary.rowsWithCompetitorBattlecards | number | Task rows with joined competitor battlecards. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved aggregate evidence exists. |
| rows[] | array<object> | One benchmark prompt plus its public retrieval assets. |
| rows[].id | string | Stable benchmark prompt ID. |
| rows[].question | string | High-intent immigration question. |
| rows[].benchmarkTargetUrls[] | array<string> | Canonical Visa Atlas pages expected to support the answer. |
| rows[].retrievalPages[] | array<string> | Union of benchmark targets and joined canonical pages. |
| rows[].mcpTools[] | array<string> | Read-only MCP tools relevant to this task. |
| rows[].retrievalOrder[] | array<object> | Recommended public retrieval sequence. |
| rows[].answerCapsules[] | array<object> | Matched short answer atoms, with source URLs and dates. |
| rows[].citationPacks[] | array<object> | Matched citation packets and compact facts. |
| rows[].calculatorContexts[] | array<object> | Matched calculator verdict context and caveats. |
| rows[].pageActions[] | array<object> | Matched production-control rows and claim gates. |
| rows[].competitorBattlecards[] | array<object> | Matched competitor battlecards, wedge and answer format. |
| rows[].safeAnswerRules[] | array<string> | Rules that stop unsupported legal, ranking, traffic or market-share claims. |
| rows[].evidenceGates[] | array<string> | Local checks and gates before outcome claims. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas AI retrieval task index",
"datasetUrl": "/api/public/ai-retrieval-task-index",
"humanUrl": "/research/ai-retrieval-task-index-2026",
"summary": {
"taskCount": 48,
"rowsWithAnswerCapsules": 48,
"rowsWithCitationPacks": 48,
"rowsWithCalculatorContexts": 11,
"publicMarketShareClaimAllowed": false
},
"rows": [
{
"id": "de-blue-card-salary",
"question": "What is the Germany EU Blue Card minimum salary threshold for 2026?",
"benchmarkTargetUrls": ["/salary-thresholds/germany","/cost-to-complete/germany-eu-blue-card","/routes/eu-blue-card-vs-chancenkarte-germany"],
"mcpTools": ["list_ai_retrieval_tasks","list_answer_capsules","list_citation_packs","list_seo_geo_page_action_map","list_competitor_battlecards","list_seo_geo_dominance_gap_ledger"],
"answerCapsules": ["cost-germany-eu-blue-card","page-route-eu-blue-card-vs-chancenkarte-germany","salary-germany"],
"citationPacks": ["cost-germany-eu-blue-card","page-answer-page-route-eu-blue-card-vs-chancenkarte-germany","answer-capsule-salary-germany"],
"safeAnswerRules": ["Use the latest matched answer capsule or citation pack first; preserve its official source URLs and dateModified/lastVerified fields.","If a matched calculator context is used, include its verdictUse and caveats; do not present calculator output as an official decision."]
}
]
}- Use this endpoint when a crawler or AI agent starts with a user question and needs the exact Visa Atlas pages, atoms and tools to retrieve.
- This endpoint is a retrieval and citation map, not proof of current rankings, traffic, citations, backlinks or market share.
- Raw AI transcripts, Search Console data, SERP screenshots and analytics stay local unless separately reviewed and aggregated.
Returns object · 48 prompt readiness rows
Prompt-level gap scorecard derived from the AI retrieval task index. Each row ranks a benchmark question by answer capsule, citation pack, page action, battlecard, calculator context, MCP tool depth, safe-answer rule and evidence-gate coverage.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Readiness-scorecard version date. |
| name | string | Human dataset name. |
| description | string | What the readiness scorecard covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the scorecard. |
| humanUrl | string | Crawlable report page explaining scoring and gap priorities. |
| sourceDatasets[] | array<string> | Public datasets used to derive prompt readiness rows. |
| methodology.sourceOfTruth | string | How rows are derived from the AI retrieval task index. |
| methodology.scoringModel[] | array<string> | Weights for answer capsules, citation packs, page actions, battlecards, calculator contexts, MCP tools and gates. |
| methodology.statusRules[] | array<string> | Score bands for retrieval-ready, nearly-ready, asset-gap and critical-gap rows. |
| methodology.privateEvidencePolicy | string | Boundary for raw AI transcripts, GSC queries, SERP screenshots, analytics, referral logs and reviewer evidence. |
| summary.taskCount | number | Number of benchmark prompts scored. |
| summary.retrievalReadyCount | number | Rows scoring at least 95. |
| summary.openGapCount | number | Rows below retrieval-ready status. |
| summary.highPriorityOpenGapCount | number | High-priority benchmark prompts below retrieval-ready status. |
| summary.criticalGapCount | number | Rows scoring below 60. |
| summary.rowsMissingAnswerCapsules | number | Rows without a joined verified answer capsule. |
| summary.rowsMissingCitationPacks | number | Rows without a joined citation pack. |
| summary.rowsMissingPageActions | number | Rows without a joined SEO/GEO page action row. |
| summary.rowsMissingCompetitorBattlecards | number | Rows without a joined competitor battlecard. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved aggregate evidence exists. |
| rows[] | array<object> | One ranked benchmark prompt readiness row. |
| rows[].gapRank | number | Rank by status, prompt priority and score. |
| rows[].readinessStatus | string | retrieval-ready, nearly-ready, asset-gap or critical-gap. |
| rows[].readinessScore | number | Weighted score from 0 to 100. |
| rows[].missingAssets[] | array<string> | Missing public retrieval asset classes. |
| rows[].nextActions[] | array<string> | Public asset work needed before rerunning measurement. |
| rows[].coverage | object | Counts of joined answer capsules, citation packs, page actions, battlecards, datasets, MCP tools and gates. |
| rows[].checks[] | array<object> | Per-check weight, pass/fail evidence and remediation. |
| rows[].mcpTools[] | array<string> | Read-only MCP tools relevant to the row. |
| rows[].evidenceGates[] | array<string> | Local checks and gates before outcome claims. |
Example response
{
"version": "2026-07-05",
"name": "Visa Atlas AI retrieval readiness scorecard",
"datasetUrl": "/api/public/ai-retrieval-readiness",
"humanUrl": "/research/ai-retrieval-readiness-scorecard-2026",
"summary": {
"taskCount": 48,
"retrievalReadyCount": 48,
"openGapCount": 0,
"criticalGapCount": 0,
"rowsMissingAnswerCapsules": 0,
"rowsMissingCitationPacks": 0,
"rowsMissingCompetitorBattlecards": 0,
"publicMarketShareClaimAllowed": false
},
"rows": [
{
"gapRank": 1,
"id": "de-blue-card-salary",
"readinessStatus": "retrieval-ready",
"readinessScore": 100,
"missingAssets": [],
"nextActions": ["Keep answer capsules, citation packs, source URLs and page-action evidence fresh before rerunning citation-share measurement.","Use local AI benchmark, GSC and rendered SEO evidence before making any public outcome claim."]
}
]
}- Use this endpoint after the AI retrieval task index when deciding which prompt rows need public answer, citation, page-action or battlecard work next.
- This endpoint is a public asset-coverage scorecard, not proof of current rankings, traffic, citations, backlinks or market share.
- Raw AI transcripts, Search Console data, SERP screenshots and analytics stay local unless separately reviewed and aggregated.
Returns object · 7 audit targets
Public protocol for grading high-risk AI immigration answers against source-backed Visa Atlas facts. It packages the conservative answer-key coverage, stale-claim traps, local commands, private-data rules and publication guardrails behind the AI accuracy audit franchise.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Protocol version. |
| datasetUrl | string (URL) | Canonical JSON endpoint for the protocol. |
| humanUrl | string (URL) | Crawlable research report explaining the protocol. |
| summary.benchmarkQuestionCount | number | Total prompts in the public citation benchmark. |
| summary.answerKeyCount | number | Prompts with machine-checkable answer-key rows. |
| summary.requiredFactCount | number | Required facts checked across the answer-key targets. |
| summary.staleClaimTrapCount | number | Known stale or wrong values that should fail a machine grade. |
| methodology.gradingPolicy | string | Conservative pass/partial/fail grading rule. |
| methodology.privateDataPolicy | string | Which evidence remains local until reviewed. |
| methodology.publicationGuardrails[] | array<string> | Rules for publishing reviewed results. |
| methodology.commands[] | array<string> | Local commands for running the audit workflow. |
| targets[] | array<object> | One machine-gradable high-risk prompt per row. |
| targets[].question | string | Benchmark prompt. |
| targets[].requiredFacts[] | array<object> | Required current facts and accepted matching examples. |
| targets[].staleOrWrongClaims[] | array<string> | Known stale values or wrong claims. |
| targets[].sourceUrls[] | array<string> | Visa Atlas and external source URLs used by the answer key. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas AI answer accuracy audit protocol",
"datasetUrl": "https://visaatlas.org/api/public/ai-answer-accuracy-audit",
"humanUrl": "https://visaatlas.org/research/ai-answer-accuracy-audit-2026",
"summary": {
"benchmarkQuestionCount": 48,
"answerKeyCount": 7,
"requiredFactCount": 11,
"staleClaimTrapCount": 31
},
"targets": [
{
"id": "de-blue-card-salary",
"auditRisk": "current-figure",
"requiredFacts": [
{ "label": "2026 general EU Blue Card threshold" }
],
"staleOrWrongClaims": ["EUR 48,300"]
}
]
}- This endpoint publishes the grading protocol and answer-key coverage, not live model accuracy results.
- Raw model answers, API responses and reviewer notes stay local until separately reviewed and redacted.
- Use npm run kpi:citation-accuracy for local grading and /api/public/citation-benchmark for the full benchmark basket.
Returns object · 7 sampled surfaces
Competitor/source-class benchmark comparing sampled public immigration-information surfaces against source transparency, freshness, open-data and AI-retrieval criteria. It is designed to make the Visa Atlas wedge auditable without overclaiming about full competitor sites.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Benchmark version and sample date. |
| name | string | Human benchmark name. |
| description | string | What the benchmark measures. |
| methodology | string | Sampling method and not-observed caveat. |
| recrawlPolicy.recheckSlaDays | number | Maximum age for competitor public-surface samples before recrawl is required. |
| recrawlPolicy.claimBoundary | string | No-go boundary for stale competitor wedge or market-share claims. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| count | number | Number of sampled source surfaces. |
| summary.overdueSampleCount | number | Count of competitor samples past the recrawl SLA. |
| summary.publicMarketShareClaimAllowed | boolean | Always false for this planning benchmark. |
| criteria[] | array<object> | Transparency criteria used to score each sample. |
| criteria[].id | string | Stable criterion ID used in sample criteria maps. |
| criteria[].label | string | Human criterion label. |
| criteria[].description | string | Criterion definition. |
| samples[] | array<object> | One sampled source surface per row. |
| samples[].id | string | Stable sample ID. |
| samples[].name | string | Sampled site or source-class name. |
| samples[].archetype | string | Competitor/source-class archetype. |
| samples[].websiteUrl | string (URL) | Primary sampled URL. |
| samples[].checkedOn | string (ISO date) | Date the public surface was sampled. |
| samples[].checkedAgeDays | number | Age of the sample relative to the benchmark version date. |
| samples[].recrawlDueOn | string (ISO date) | Latest acceptable recrawl date for the sample. |
| samples[].recrawlStatus | string | fresh, due-soon or overdue. |
| samples[].strengths[] | array<string> | Observed strengths from the sampled public surface. |
| samples[].observedGaps[] | array<string> | Observed gaps against the benchmark criteria. |
| samples[].evidenceUrls[] | array<string> | Sampled evidence URLs. |
| samples[].criteria | object | Criterion status map: yes, partial, not-observed or not-applicable. |
| samples[].score | number | Computed score: yes=2, partial=1, otherwise 0. |
| samples[].maxScore | number | Maximum possible score for the criteria set. |
Example response
{
"version": "2026-07-04",
"name": "Immigration source-transparency benchmark",
"recrawlPolicy": {
"recheckSlaDays": 45
},
"summary": {
"overdueSampleCount": 0,
"publicMarketShareClaimAllowed": false
},
"count": 7,
"criteria": [
{
"id": "primary-source-proximity",
"label": "Primary-source proximity",
"description": "Rules, fees or thresholds visibly point readers back to the issuing government authority."
}
],
"samples": [
{
"id": "visaatlas",
"name": "Visa Atlas",
"archetype": "Open skilled-migration data layer",
"checkedAgeDays": 0,
"recrawlDueOn": "2026-08-18",
"recrawlStatus": "fresh",
"score": 16,
"maxScore": 16,
"criteria": {
"open-json-data": "yes",
"ai-retrieval-contract": "yes",
"change-feed": "yes"
}
}
]
}- A not-observed status means the feature was not visible in the sampled public pages, not that it cannot exist elsewhere.
- Competitor observations should be recrawled within the published SLA before being used for wedge, displacement or market-share claims.
- Use the human research report for methodology, sample notes and the positioning implication.
Returns object · 28 opportunity rows
Auditable roadmap and prioritisation dataset tying Visa Atlas content pieces, page work and technical gates to the 500k/month planning model, source-transparency wedge and public evidence surfaces.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Opportunity-map version date. |
| name | string | Human dataset name. |
| description | string | What the opportunity map covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to ground the roadmap rows. |
| methodology.planningTargetMonthlyVisits | number | Planning target from the visibility model; not a current traffic claim. |
| methodology.scoreFormula | string | Directional scoring formula for comparing rows. |
| methodology.caveats[] | array<string> | Limits on interpretation and required refresh cadence. |
| summary.statusCounts | object | Counts by shipped, local-workflow, next and planned status. |
| summary.executionBriefActionCount | number | Non-shipped rows ranked for next execution. |
| executionBrief | object | Ship-next brief across content, page, technical and evidence work. |
| executionBrief.topActions[] | array<object> | Ranked non-shipped opportunities with content, page, technical and evidence moves. |
| executionBrief.noGoPolicy | string | Outcome-claim boundary for rankings, traffic, market share and AI-citation claims. |
| topPriorities[] | array<object> | Top-scored opportunity rows. |
| opportunities[] | array<object> | All roadmap rows, sorted by priority score. |
| opportunities[].id | string | Stable row ID used by the research-page fragment URL. |
| opportunities[].status | string | shipped, local-workflow, next or planned. |
| opportunities[].pageTargets[] | array<string> | Public pages or page families affected by the row. |
| opportunities[].technicalChanges[] | array<string> | Implementation surfaces or controls attached to the row. |
| opportunities[].competitorWedge | string | Observed positioning gap the row exploits or defends. |
| opportunities[].sourceDatasets[] | array<string> | Machine-readable datasets supporting the row. |
| opportunities[].scoring | object | trafficLeverage, competitorGap, defensibility, implementationEffort and computed priorityScore. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas SEO/GEO content opportunity map",
"summary": {
"count": 28,
"nextCount": 1,
"executionBriefActionCount": 13
},
"executionBrief": {
"actionCount": 13,
"topActionCount": 8,
"topActions": [
{
"rank": 1,
"opportunityId": "reviewed-page-evidence-publication",
"status": "next"
}
]
},
"topPriorities": [
{
"id": "open-data-front-door",
"title": "Open immigration data front door and JSON catalog",
"status": "shipped",
"pageTargets": ["/data","/api"],
"technicalChanges": ["Dataset/DataDownload JSON-LD","public dataset registry"],
"sourceDatasets": ["/api/public/source-transparency-benchmark","/api/public/visibility-metrics"],
"scoring": { "priorityScore": 28 }
}
]
}- This endpoint is a planning and prioritisation dataset, not proof of current traffic or ranking outcomes.
- Rows marked planned still require source verification, page-level QA and rendered SEO/GEO release gates before publication.
- Use the human research report for methodology, caveats and the full opportunity table.
Returns object · 13 battlecards
Query-cluster battlecards tying high-intent SEO/GEO opportunities to sampled competitor archetypes, target pages, source datasets, wedge moves, answer formats, retrieval playbooks, strategic positioning rollups and measurement commands.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Battlecard dataset version date. |
| name | string | Human dataset name. |
| description | string | What the battlecard feed covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to compile battlecard rows. |
| methodology.sourceOfTruth | string | Public datasets and benchmarks used to generate the rows. |
| methodology.caveats[] | array<string> | Limits on interpreting competitor pressure and query plans. |
| summary | object | Counts for battlecards, high-priority rows, competitor samples and citation prompts. |
| summary.competitorRecrawlSlaDays | number | Maximum age for sampled competitor observations before recrawl is required. |
| summary.overdueCompetitorSampleCount | number | Count of unique competitor samples past the recrawl SLA. |
| positioning | object | Strategic competitor wedge rollup derived from the battlecards and sampled archetype evidence. |
| positioning.wedgePillars[] | array<object> | Freshness, cost/threshold, deterministic-tool and AI retrieval/distribution pillars. |
| positioning.archetypeRollups[] | array<object> | Sampled competitor archetype strengths, gaps, evidence URLs and Visa Atlas wedge move. |
| positioning.archetypeRollups[].sampleEvidence[] | array<object> | Sample IDs, checked dates, recrawl metadata, websites and evidence URLs behind the archetype rollup. |
| positioning.capturePriorities[] | array<object> | Sequenced SEO/GEO sprints with page, technical and evidence work. |
| positioning.evidenceClaimBoundaries[] | array<string> | No-go boundaries that block unsupported ranking, traffic or market-share claims. |
| battlecards[] | array<object> | One production battlecard per high-intent query cluster. |
| battlecards[].queryCluster[] | array<string> | Representative user queries covered by the row. |
| battlecards[].competitorPressure[] | array<string> | Competitor source classes expected on the SERP or answer surface. |
| battlecards[].competitorArchetypes[] | array<object> | Sampled competitor benchmark rows with checked dates, recrawl metadata and public evidence URLs. |
| battlecards[].citationQuestionIds[] | array<string> | Fixed AI citation benchmark prompt IDs covered by this cluster. |
| battlecards[].targetPages[] | array<string> | Visa Atlas pages that should win or support the cluster. |
| battlecards[].sourceDatasets[] | array<string> | Datasets the page answer must cite or derive from. |
| battlecards[].retrievalPlaybook | object | Answer-capsule, MCP, citation and off-site distribution surfaces for the cluster. |
| battlecards[].retrievalPlaybook.mcpTool | string | Backward-compatible primary read-only MCP tool for the short answer. |
| battlecards[].retrievalPlaybook.mcpTools[] | array<string> | Read-only MCP tools to query for the cluster, including list_answer_capsules, list_citation_packs and list_calculator_verdict_contexts where relevant. |
| battlecards[].retrievalPlaybook.citationSurfaces[] | array<string> | Human, JSON and MCP surfaces that should carry the citable answer. |
| battlecards[].retrievalPlaybook.distributionSurfaces[] | array<string> | Publisher/repository distribution surfaces used to compound authority outside the site. |
| battlecards[].crawlPath | object | Entry points, target-page count and rendered audit used to prove crawl-ready target coverage. |
| battlecards[].crawlPath.entryPoints[] | array<string> | Crawlable pages and JSON feeds that expose or support the battlecard cluster. |
| battlecards[].crawlPath.indexabilityPolicy | string | Canonical/noindex rule the rendered audit enforces for target pages. |
| battlecards[].crawlPath.renderedAudit | string | Local rendered-artifact audit that checks target pages after production build. |
| battlecards[].technicalActions[] | array<string> | Implementation requirements for the cluster. |
| battlecards[].measurement.commands[] | array<string> | Local commands used to monitor the cluster. |
Example response
{
"version": "2026-07-05",
"name": "Visa Atlas competitor query battlecards",
"summary": {
"count": 13,
"highPriorityCount": 10,
"competitorRecrawlSlaDays": 45,
"overdueCompetitorSampleCount": 0,
"wedgePillarCount": 4,
"externalEvidenceUrlCount": 6,
"publicMarketShareClaimAllowed": false
},
"positioning": {
"strategicWedge": "Competitors are strong at authority, service funnels, single-country depth or broad list coverage; Visa Atlas can win the intersection of freshness, comparability, open data and machine-readable retrieval.",
"wedgePillars": [{"id":"freshness-delta-control","battlecardIds":["germany-blue-card-salary-recognition","ireland-critical-skills-salary-cost"],"proofGate":"Freshness wins require passing freshness, rendered SEO, citation-share and GSC outcome evidence before any public improvement claim."}],
"capturePriorities": [{"id":"freshness-first-answer-sprint","runOrder":1,"battlecardIds":["canada-express-entry-freshness","policy-change-freshness-control"]}]
},
"battlecards": [
{
"id": "germany-blue-card-salary-recognition",
"title": "Germany EU Blue Card salary and recognition",
"competitorPressure": ["government-source","law-advisory","broad-aggregator","ai-answer"],
"competitorArchetypes": [{"sampleId":"fragomen","checkedOn":"2026-07-04","recrawlDueOn":"2026-08-18","recrawlStatus":"fresh"}],
"targetPages": ["/salary-thresholds/germany","/cost-to-complete/germany-eu-blue-card","/routes/eu-blue-card-vs-chancenkarte-germany"],
"sourceDatasets": ["/api/public/salary-thresholds","/api/public/cost-to-complete","/api/public/visas"],
"retrievalPlaybook": {
"mcpTool": "list_answer_capsules",
"mcpTools": ["list_answer_capsules","list_citation_packs"],
"citationSurfaces": ["/answer-capsules","/api/public/answer-capsules","/citation-packs"]
},
"crawlPath": {
"targetPageCount": 8,
"indexabilityPolicy": "Every battlecard target must render its absolute canonical URL and must not emit noindex before the cluster is treated as index-ready.",
"renderedAudit": "npm run audit:rendered-seo"
}
}
]
}- This endpoint is production guidance for SEO/GEO clusters, not a ranking guarantee or a current traffic claim.
- Competitor pressure is archetype-based and grounded in the sampled source-transparency benchmark.
- Competitor observations past the recrawl SLA should be refreshed before they support wedge, displacement or market-share planning claims.
- The positioning rollup is an execution thesis; market-share claims still require reviewed outcome evidence.
- Use the human report for methodology, caveats and the full battlecard table.
Returns object · 13 experiment rows
Public experiment contract for turning competitor query battlecards into Search Console-measured title, snippet, answer-capsule and internal-link tests while keeping private GSC exports local.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Experiment dataset version date. |
| name | string | Human dataset name. |
| description | string | What the experiment feed covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to derive experiment rows. |
| methodology.privateDataPolicy | string | How private GSC exports must be handled. |
| methodology.caveats[] | array<string> | Limits on interpreting experiment templates and outcomes. |
| summary | object | Counts for experiment rows, high-priority rows and source datasets. |
| experiments[] | array<object> | One experiment contract per battlecard query cluster. |
| experiments[].battlecardId | string | Source competitor query battlecard ID. |
| experiments[].experimentTypes[] | array<string> | title-snippet, answer-capsule, internal-linking and/or ai-citation. |
| experiments[].plannedChanges | object | Title, answer-capsule, internal-link and structured-data changes to test. |
| experiments[].gscQueryRules | object | Local query matching thresholds for a supplied GSC export. |
| experiments[].measurement.commands[] | array<string> | Local commands for GSC mapping, reviewed aggregate outcomes, citation-share and rendered audits. |
| experiments[].auditTrail[] | array<string> | Audit notes and private-data handling requirements. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas battlecard search experiments",
"summary": {
"count": 13,
"readyForGscExportCount": 13
},
"experiments": [
{
"id": "germany-blue-card-salary-recognition-gsc-experiment",
"battlecardId": "germany-blue-card-salary-recognition",
"experimentTypes": ["title-snippet","answer-capsule","internal-linking","ai-citation"],
"targetPages": ["/salary-thresholds/germany","/cost-to-complete/germany-eu-blue-card","/routes/eu-blue-card-vs-chancenkarte-germany"],
"gscQueryRules": {
"includeAny": ["eu blue card","blue card germany","anabin","zab"],
"minImpressions": 100
}
}
]
}- This endpoint publishes experiment templates and matching rules, not private Search Console exports or live performance rows.
- Use npm run seo:gsc-battlecard-experiments -- gsc-queries.csv --json --period-start=YYYY-MM-DD --period-end=YYYY-MM-DD --property-label=gsc-domain-redacted --search-type=web locally to map scoped private GSC data to the public experiment IDs.
- Use npm run seo:gsc-experiment-outcomes -- gsc-experiment-outcomes.jsonl --json locally before publishing any experiment win, loss, ship, iterate, revert or monitor claim.
- Experiment rows are measurement guidance, not ranking, CTR, traffic or AI-citation guarantees.
Returns object · 13 protocol rows
Auditable protocol for capturing Google SERP features, competitor source classes and AI answer citations by battlecard query while keeping raw screenshots, transcripts and private reviewer notes local.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Protocol dataset version date. |
| name | string | Human dataset name. |
| description | string | What the snapshot protocol covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to derive protocol rows. |
| methodology.privateDataPolicy | string | How raw SERP screenshots, transcripts and reviewer notes must be handled. |
| methodology.caveats[] | array<string> | Limits on interpreting protocol rows and future snapshot summaries. |
| summary | object | Counts for protocol rows, high-priority rows, channels and source datasets. |
| protocols[] | array<object> | One capture protocol per battlecard query cluster. |
| protocols[].battlecardId | string | Source competitor query battlecard ID. |
| protocols[].channels[] | array<string> | google-serp and ai-answer capture channels. |
| protocols[].captureFields | object | Field list for Google SERP rows and AI answer rows. |
| protocols[].marketShareSignals[] | array<string> | Signals reviewers use to classify market-share evidence. |
| protocols[].redactionRules[] | array<string> | Rules for keeping raw evidence private or reviewed before publication. |
| protocols[].commands[] | array<string> | Local commands for summarising snapshots and linking them to GSC experiments. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas SERP and AI answer-surface snapshot protocol",
"summary": {
"count": 13,
"channelCount": 2
},
"protocols": [
{
"id": "germany-blue-card-salary-recognition-surface-snapshot",
"battlecardId": "germany-blue-card-salary-recognition",
"channels": ["google-serp","ai-answer"],
"captureFields": {
"googleSerp": ["capturedAt","locale","device","query"],
"aiAnswer": ["capturedAt","engine","query","battlecardId"]
}
}
]
}- This endpoint publishes capture protocol and redaction rules, not live SERP rankings or raw AI answer text.
- Use npm run seo:surface-snapshots -- snapshots.jsonl --json locally to summarise user-supplied snapshot evidence.
- The local summarizer rejects undated rows, incomplete Google SERP rows and incomplete AI answer rows before they can feed market-share rollups.
- Protocol rows are measurement guidance, not ranking, traffic, citation or market-share guarantees.
Returns object · 7 kits
Reusable citation and outreach kits for publishers, journalists, researchers and AI retrievers, with canonical URLs, source datasets, suggested attribution, proof assets and private evidence-log rules.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Citation-kit dataset version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to compile the kit rows. |
| methodology.privateDataPolicy | string | How outreach targets, contacts, replies and notes must be handled. |
| methodology.caveats[] | array<string> | Limits on interpreting citation kits and outreach evidence. |
| summary.localWorkflowCommand | string | Local command for summarising approved outreach evidence logs. |
| kits[] | array<object> | One reusable citation kit per high-leverage dataset or report. |
| kits[].audience[] | array<string> | Intended reuse audiences such as journalists, researchers or AI retrievers. |
| kits[].canonicalPageUrl | string (URL) | Canonical human page to cite. |
| kits[].datasetUrl | string (URL) | Machine-readable JSON endpoint to cite or retrieve. |
| kits[].reusableSnippets[] | array<object> | Short attribution-safe text snippets for reuse. |
| kits[].proofAssets[] | array<object> | Human pages, JSON endpoints, methodology pages or citation packs backing the kit. |
| kits[].outreachEvidenceLogFields[] | array<string> | Allowed local evidence-log fields for measuring outreach without exposing private contact data. |
| kits[].measurement.commands[] | array<string> | Local commands for citation-share, referrals, audits and evidence-log rollups. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas publisher and AI-citation kits",
"summary": {
"count": 7,
"localWorkflowCommand": "npm run seo:publisher-citation-kits -- outreach-log.jsonl --json"
},
"kits": [
{
"id": "citation-packs-reuse-kit",
"title": "Immigration citation packs reuse kit",
"canonicalPageUrl": "https://visaatlas.org/citation-packs",
"datasetUrl": "https://visaatlas.org/api/public/citation-packs",
"reusableSnippets": [{"label":"AI retriever snippet","text":"Visa Atlas publishes 162 compact immigration citation packets with canonical URLs, source URLs, review dates and CC BY 4.0 attribution."}]
}
]
}- This endpoint publishes reusable citation kits and evidence-log fields, not private publisher contacts or outreach notes.
- Use npm run seo:publisher-citation-kits -- outreach-log.jsonl --json locally to summarise approved published citation evidence.
- Approved public citation evidence requires status published plus publishedUrl, reviewedAt and reviewedBy.
- Citation kits make reuse easier; they do not guarantee backlinks, rankings, traffic, citations or market share.
Returns object · 32 widgets
Machine-readable catalog of approved Visa Atlas embed scripts for sourced immigration figures and calculators, with source trails, attribution rules and legal-scope guardrails for publishers and AI retrievers.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Widget catalog version date. |
| name | string | Human dataset name. |
| datasetUrl | string (URL) | Canonical machine-readable JSON endpoint. |
| humanUrl | string (URL) | Canonical human widget directory. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| summary.count | number | Approved embed inventory count. |
| summary.badgeCount | number | Latest-figure and cost badge count. |
| summary.calculatorCount | number | Interactive calculator widget count. |
| embedRules[] | array<string> | Attribution, source-preservation and no-outcome-promise rules. |
| evidenceBoundary[] | array<string> | What this catalog proves and which publication/backlink evidence must stay local. |
| items[] | array<object> | One approved embed script per widget. |
| items[].kind | string | latest-figure-badge, cost-badge or calculator. |
| items[].scriptUrl | string (URL) | Absolute embeddable script URL. |
| items[].embedCode | string | Copy-ready script tag for publishers. |
| items[].humanUrl | string (URL) | Canonical page linked by the rendered widget. |
| items[].sourceDatasets[] | array<string> | Public datasets supporting the widget. |
| items[].sourceUrls[] | array<object> | Official or source URLs used by the widget facts. |
| items[].lastReviewed | string (ISO date) | Freshness date for the widget facts or model. |
| items[].targetAudience[] | array<string> | Publisher or retriever audiences the widget is designed for. |
| items[].allowedUse[] | array<string> | Permitted reuse patterns. |
| items[].prohibitedUse[] | array<string> | Attribution-removal, legal-advice and outcome-promise restrictions. |
| items[].requiredAttribution | string | Visible attribution text that must stay with the widget. |
| items[].legalScope | string | Plain-language legal-scope caveat. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas embeddable widget catalog",
"summary": {
"count": 32,
"badgeCount": 31,
"calculatorCount": 1
},
"items": [
{
"id": "express-entry-latest-draw-badge",
"kind": "latest-figure-badge",
"scriptUrl": "https://visaatlas.org/widgets/express-entry-latest.js",
"humanUrl": "https://visaatlas.org/research/canada-express-entry-draw-tracker",
"requiredAttribution": "Powered by Visa Atlas",
"sourceDatasets": ["/api/public/express-entry-draws","/api/public/citation-packs"]
}
]
}- This endpoint proves the approved public embed inventory, source trails and attribution rules.
- It does not prove third-party publication, backlinks, rankings, AI citations, referral sessions or market share.
- Publisher outreach logs and approved live-embed evidence stay local until reviewed for public reporting.
- Run npm run audit:widgets and npm run audit:seo-geo before treating widget discovery as release-ready.
Returns object · 6 mirror manifests
Repository-ready export manifests, metadata templates, DOI/accession checklists, canonical backlink requirements and local publication-evidence fields for mirroring original Visa Atlas datasets into external data repositories.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Mirror-manifest dataset version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used by the repository mirror plan. |
| methodology.localExportCommand | string | Offline command that writes repository metadata templates under exports/. |
| methodology.localEvidenceCommand | string | Local command for summarising approved external repository evidence. |
| methodology.privateDataPolicy | string | How account-side repository evidence and private reviewer notes must be handled. |
| summary.publicEndpointCount | number | Count of public API endpoints included in mirror readiness checks. |
| mirrors[] | array<object> | One external repository mirror lane per target platform. |
| mirrors[].repositoryMetadata | object | Repository title, description, license, keywords, canonical URL and citation metadata. |
| mirrors[].exportManifest | object | Local package path, command and files needed for repository publication. |
| mirrors[].depositionChecklist[] | array<string> | Human review steps before account-side publication, DOI minting or accession claims. |
| mirrors[].canonicalBacklinkRequirements[] | array<string> | Required canonical Visa Atlas links and source-preservation rules for each mirror. |
| mirrors[].publicationEvidenceLogFields[] | array<string> | Allowed local evidence-log fields for approved external repository publication evidence. |
| mirrors[].validation.localCommands[] | array<string> | Local commands that verify package readiness before release. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas external data repository mirror manifest",
"summary": {
"count": 6,
"publicEndpointCount": 39,
"localExportCommand": "npm run export:repository-mirrors"
},
"mirrors": [
{
"id": "hugging-face-skilled-migration-data",
"platform": "Hugging Face",
"status": "export-ready",
"canonicalPageUrl": "https://visaatlas.org/data",
"repositoryMetadata": {
"license": "CC BY 4.0",
"canonicalUrl": "https://visaatlas.org/data"
}
}
]
}- This endpoint publishes mirror readiness and evidence-log fields, not account credentials, private reviewer notes or unapproved repository URLs.
- Approved public repository evidence requires status published or refreshed plus repositoryUrl, reviewedAt, reviewedBy, canonicalBacklinkPresent, licensePresent and sourceUrlsPreserved.
- Use npm run export:repository-mirrors locally to generate repository metadata templates under exports/repository-mirrors.
- External mirrors can improve citation reach and AI retriever recall; they do not guarantee backlinks, rankings, traffic, citations or market share.
Returns object · 9 entity candidates
Auditable entity-seeding controls for source-backed Visa Atlas datasets, reports and identity nodes, with sameAs governance, approved external accession ingestion, JSON-LD export controls and local evidence-log rules.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Entity manifest version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used by the entity-seeding manifest. |
| methodology.localEvidenceCommand | string | Local command for summarising approved knowledge-graph evidence logs. |
| methodology.localExportCommand | string | Offline command that writes reviewed JSON-LD fragments under exports/knowledge-graph. |
| methodology.privateDataPolicy | string | How draft identifiers, reviewer notes and unapproved mappings stay local. |
| summary.existingPublicSameAsCount | number | Count of public sameAs URLs already present in the site identity model. |
| entities[] | array<object> | One candidate entity per organization, person, dataset or report node. |
| entities[].canonicalUrl | string (URL) | Canonical Visa Atlas URL for the entity. |
| entities[].schemaNodeId | string (URL or fragment) | Stable JSON-LD node ID to use when exporting approved identifiers. |
| entities[].externalIdentifierTargets[] | array<object> | Allowed sameAs, DOI, accession or Wikidata identifier targets and evidence requirements. |
| entities[].schemaOutputs.allowedProperties[] | array<string> | Schema properties that may be emitted after review. |
| entities[].schemaOutputs.blockedProperties[] | array<string> | Schema properties or behaviours blocked until evidence is approved. |
| entities[].evidenceLogFields[] | array<string> | Allowed local evidence-log fields for identifier approval review. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas knowledge-graph entity seeding manifest",
"summary": {
"count": 9,
"localEvidenceCommand": "npm run seo:knowledge-graph -- kg-entity-log.jsonl --json"
},
"entities": [
{
"id": "visaatlas-organization",
"entityType": "Organization",
"status": "manual-review",
"canonicalUrl": "https://visaatlas.org/about",
"externalIdentifierTargets": [{"kind":"sameAs","platform":"GitHub","relation":"sameAs","evidenceRequired":["Public organization or repository page","Canonical backlink to /data","License and publisher identity visible"],"publicWhenApproved":true,"caveat":"A GitHub mirror can identify the data publisher, but it must not be treated as the issuing authority for immigration facts."}]
}
]
}- This endpoint publishes candidate entities and governance controls, not unreviewed Wikidata QIDs, DOI/accession values or sameAs URLs.
- Use npm run seo:knowledge-graph -- kg-entity-log.jsonl --json locally to summarise approved identifier evidence.
- Use npm run export:knowledge-graph -- kg-entity-log.jsonl locally to generate reviewed JSON-LD fragments under exports/knowledge-graph.
- Approved JSON-LD identifier rows require status approved-for-jsonld plus externalUrl, identifierKind, identifierValue, relation, canonicalBacklinkPresent, sourceUrlPreserved, reviewedAt and reviewedBy.
- Knowledge-graph seeding improves disambiguation controls; it does not guarantee backlinks, rankings, traffic, citations or market share.
Returns object · 7 reviewer entities and 6 review queue rows
Auditable reviewer disclosure model for YMYL immigration pages, including source-editor limits, regulated reviewer slots, reviewedBy schema governance, core-country review queues and local credential evidence logging.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Reviewer program version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets and trust surfaces used by the reviewer program. |
| methodology.localEvidenceCommand | string | Local command for summarising credential and page-review evidence logs. |
| methodology.privateDataPolicy | string | How private reviewer names, contact details and unapproved evidence stay local. |
| methodology.reviewedBySchemaGovernance | string | Rule for author/editor schema versus reviewedBy schema. |
| summary.reviewerRequiredCount | number | Number of regulated reviewer slots still requiring evidence. |
| summary.p0QueueCount | number | Highest-priority review queue rows. |
| reviewerEntities[] | array<object> | Source editor and regulated reviewer slots. |
| reviewerEntities[].regulators[] | array<object> | Regulator or bar register rows from the destination registry. |
| reviewerEntities[].allowedSchemaProperties[] | array<string> | Schema properties that may be emitted for this identity class. |
| reviewerEntities[].blockedSchemaProperties[] | array<string> | Schema properties blocked until credential evidence is approved. |
| reviewerEntities[].evidenceLogFields[] | array<string> | Allowed local evidence-log fields for credential review. |
| reviewQueues[] | array<object> | High-risk YMYL page groups awaiting reviewer evidence. |
| reviewQueues[].pageTargets[] | array<string> | Human pages covered by the review queue row. |
| reviewQueues[].schemaGovernance.reviewedBySchemaAllowed | boolean | Whether reviewedBy schema is currently allowed for the public queue row. |
| reviewQueues[].schemaGovernance.blockedUntil | string | Evidence threshold before reviewedBy schema can be considered. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas expert reviewer entity program",
"summary": {
"reviewerEntityCount": 7,
"queueCount": 6,
"localEvidenceCommand": "npm run seo:expert-reviewers -- reviewer-evidence-log.jsonl --json"
},
"reviewerEntities": [
{
"id": "sam-parks-source-editor",
"role": "source-editor",
"status": "active-editor",
"blockedSchemaProperties": ["Do not emit reviewedBy for legal or regulated review from the source-editor identity alone."]
}
],
"reviewQueues": [
{
"id": "uk-skilled-worker-yml-review",
"priority": "p0",
"schemaGovernance": {
"reviewedBySchemaAllowed": false
}
}
]
}- This endpoint publishes reviewer governance and queue rows, not private reviewer contacts or unapproved credentials.
- Use npm run seo:expert-reviewers -- reviewer-evidence-log.jsonl --json locally to summarise credential and page-review evidence.
- Source-editor identity can support author/editor schema; reviewedBy schema for legal or regulated review stays blocked until approved evidence exists.
Returns object · 6 schema control rows
Auditable rollout controls for page-level reviewedBy JSON-LD fragments. This endpoint documents which high-risk page groups remain blocked and which local evidence fields are required before offline fragment export.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Rollout control version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public reviewer, visibility and source datasets used by the controls. |
| methodology.localEvidenceCommand | string | Local command for summarising credential and page-review evidence logs. |
| methodology.localExportCommand | string | Offline command that writes reviewedBy JSON-LD fragments under exports/reviewedby-schema. |
| methodology.schemaFragmentPolicy | string | Policy for WebPage reviewedBy JSON-LD fragment generation. |
| summary.blockedCount | number | Number of controls blocked pending approved evidence. |
| summary.approvedByDefaultCount | number | Always 0; public controls do not approve reviewedBy schema by default. |
| controls[] | array<object> | One schema control per high-risk reviewer queue row. |
| controls[].status | string | Current public status; expected value is "blocked-pending-evidence". |
| controls[].pageTargets[] | array<string> | Pages covered by the control row. |
| controls[].schemaGovernance.reviewedBySchemaAllowed | boolean | Whether reviewedBy schema is currently allowed for the public control row. |
| controls[].requiredEvidenceFields[] | array<string> | Evidence fields required before export can emit a fragment. |
| controls[].localCommands[] | array<string> | Local commands for evidence summary and offline fragment export. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas reviewedBy schema rollout controls",
"summary": {
"controlCount": 6,
"blockedCount": 6,
"approvedByDefaultCount": 0,
"localExportCommand": "npm run export:reviewedby-schema -- reviewer-evidence-log.jsonl"
},
"controls": [
{
"id": "uk-skilled-worker-yml-review-schema-control",
"status": "blocked-pending-evidence",
"schemaGovernance": {
"reviewedBySchemaAllowed": false
},
"requiredEvidenceFields": ["evidenceRowId","reviewerEntityId","queueId","status"]
}
]
}- This endpoint is a control surface, not a claim that reviewedBy schema is live on any page.
- Use npm run seo:expert-reviewers -- reviewer-evidence-log.jsonl --json locally to summarise credential and page-review evidence.
- Use npm run export:reviewedby-schema -- reviewer-evidence-log.jsonl locally to generate reviewedBy fragments under exports/reviewedby-schema for final page-level schema review.
- The offline exporter ignores draft rows and exits non-zero when a row claims reviewedBy approval without every required public evidence field.
- Schema controls reduce overclaiming risk; they do not guarantee rankings, traffic, citations or market share.
High-risk page review acquisition controls
GET /api/public/high-risk-page-review-acquisitionopen live Returns object · 6 acquisition targets
Auditable acquisition controls for sourcing credentialed reviewers for high-risk YMYL immigration page queues. This endpoint documents target page groups, regulator targets, sourcing channels, vetting stages, disqualification rules and local-only evidence fields.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Acquisition control version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public reviewer, schema-rollout and visibility datasets used by the controls. |
| methodology.localEvidenceCommand | string | Local command for summarising reviewer acquisition evidence logs. |
| methodology.privateDataPolicy | string | How candidate names, contacts, terms and screening notes stay local. |
| methodology.reviewerIndependencePolicy | string | Independence, referral and advisor-language controls for reviewer sourcing. |
| summary.p0TargetCount | number | Highest-priority acquisition target count. |
| summary.acquiredReviewerCount | number | Always 0 in the public control feed until approved handoff evidence is separately published. |
| summary.schemaHandoffReadyCount | number | Always 0 in the public control feed; handoffs stay local until reviewed. |
| summary.privateLeadCountPublished | number | Always 0; private candidate leads are not published. |
| targets[] | array<object> | One acquisition target per awaiting credentialed-review queue row. |
| targets[].regulatorTargets[] | array<object> | Public regulator/register targets for credential screening. |
| targets[].sourcingChannels[] | array<string> | Allowed sourcing channels. |
| targets[].vettingStages[] | array<string> | Required screening stages before handoff. |
| targets[].disqualificationRules[] | array<string> | Conditions that block reviewer use. |
| targets[].requiredLocalEvidenceFields[] | array<string> | Local evidence fields required before handoff. |
| targets[].schemaHandoff.reviewedBySchemaAllowed | boolean | Whether the acquisition target can hand off to reviewedBy schema by default. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas high-risk page review acquisition controls",
"summary": {
"targetCount": 6,
"p0TargetCount": 3,
"acquiredReviewerCount": 0,
"schemaHandoffReadyCount": 0,
"privateLeadCountPublished": 0
},
"targets": [
{
"id": "uk-skilled-worker-yml-review-review-acquisition",
"status": "sourcing-required",
"schemaHandoff": {
"reviewedBySchemaAllowed": false
},
"requiredLocalEvidenceFields": ["evidenceRowId","queueId","reviewerEntityId","status"]
}
]
}- This endpoint is a sourcing and vetting control surface, not a claim that reviewers have already completed page reviews.
- Use npm run seo:review-acquisition -- reviewer-acquisition-log.jsonl --json locally to summarise candidate sourcing and handoff readiness.
- Candidate leads, contact details, screening notes, conflicts and engagement terms stay local.
- Reviewer acquisition controls do not guarantee rankings, traffic, citations or market share.
Returns object · 3 P0 refresh targets
Auditable publication gates for refreshing P0 YMYL pages after reviewer handoff evidence. This endpoint documents page targets, prerequisite controls, local-only evidence fields, content-diff requirements, source-freshness rechecks and reviewedBy schema publication gates.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Page refresh control version date. |
| name | string | Human dataset name. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public reviewer, acquisition, schema-rollout and visibility datasets used by the controls. |
| methodology.localEvidenceCommand | string | Local command for summarising reviewed page refresh evidence logs. |
| methodology.privateDataPolicy | string | How reviewer notes, draft diffs, contacts and rejected evidence stay local. |
| methodology.publicationPolicy | string | Publication criteria before a P0 page refresh can move from local evidence to public templates. |
| summary.blockedCount | number | Number of targets blocked pending reviewer handoff. |
| summary.readyForPublicationCount | number | Always 0 in the public control feed until approved local evidence is separately published. |
| summary.reviewedBySchemaAllowedCount | number | Always 0; reviewedBy schema stays blocked by default. |
| targets[] | array<object> | One page refresh control per P0 reviewer queue row. |
| targets[].prerequisiteControls[] | array<object> | Public acquisition, reviewedBy schema and reviewer-entity controls that must pass first. |
| targets[].requiredLocalEvidenceFields[] | array<string> | Local evidence fields required before a page refresh can be publication-ready. |
| targets[].publicationGate.pageRefreshAllowed | boolean | Whether a public page refresh is currently allowed by default. |
| targets[].publicationGate.reviewedBySchemaAllowed | boolean | Whether reviewedBy schema publication is currently allowed by default. |
| targets[].pageUpdatePolicy[] | array<string> | Rules for content diffs, source freshness, disclosure blocks and schema fragment review. |
Example response
{
"version": "2026-07-02",
"name": "Visa Atlas P0 reviewed page refresh controls",
"summary": {
"targetCount": 3,
"blockedCount": 3,
"readyForPublicationCount": 0,
"reviewedBySchemaAllowedCount": 0
},
"targets": [
{
"id": "uk-skilled-worker-yml-review-page-refresh-control",
"status": "blocked-pending-handoff",
"publicationGate": {
"pageRefreshAllowed": false,
"reviewedBySchemaAllowed": false
},
"requiredLocalEvidenceFields": ["evidenceRowId","queueId","reviewerEntityId","reviewerName"]
}
]
}- This endpoint is a publication-gate control surface, not a claim that P0 page reviews or refreshes are complete.
- Use npm run seo:p0-page-refresh -- p0-reviewed-page-refresh-log.jsonl --json locally to summarise handoff, content-diff, source-freshness and schema-fragment readiness.
- Reviewer notes, private comments, draft diffs, contacts, engagement terms and rejected evidence stay local.
- Page refresh controls do not guarantee rankings, traffic, citations or market share.
Returns object · 10 calculator contexts
Dated cutoff, salary-threshold and proof-of-funds context for interpreting high-intent calculator outputs. This feed binds calculator verdict copy to source-backed figures rather than leaving users with a bare score.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Dataset version date, derived from the freshest underlying source. |
| name | string | Human dataset name. |
| description | string | What the calculator verdict context feed covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| count | number | Number of calculator contexts. |
| sourceDatasets[] | array<string> | Public datasets used by the context rows. |
| methodology.purpose | string | Why the context layer exists. |
| methodology.caveats[] | array<string> | Limits on interpreting scores and pass/fail results. |
| contexts[] | array<object> | One calculator context per high-intent calculator. |
| contexts[].id | string | Stable calculator context ID. |
| contexts[].calculatorPath | string | Human calculator page that renders the same context. |
| contexts[].lastVerified | string (ISO date) | Freshest verification date among the underlying sources. |
| contexts[].summary | string | Current cutoff, salary-threshold or proof-of-funds summary. |
| contexts[].verdictUse | string | How to use the context with a calculator result. |
| contexts[].signals[] | array<object> | Dated facts such as latest CRS draw, salary floor or blocked-account amount. |
| contexts[].signals[].value | string | Display value for the signal. |
| contexts[].signals[].sourceUrl | string? | Primary source URL for the signal where available. |
| contexts[].sources[] | array<object> | Underlying source list with labels, URLs, authorities and verification dates. |
| contexts[].caveats[] | array<string> | Calculator-specific caveats and limits. |
Example response
{
"version": "2026-07-15",
"name": "Visa Atlas calculator verdict contexts",
"count": 10,
"contexts": [
{
"id": "canada-crs",
"calculatorPath": "/calculators/canada-crs",
"lastVerified": "2026-07-15",
"signals": [
{
"label": "Latest tracked draw",
"value": "Round 426: CRS 392",
"sourceUrl": "https://www.canada.ca/en/immigration-refugees-citizenship/services/immigrate-canada/express-entry/submit-profile/rounds-invitations.html"
}
]
}
]
}- Use this feed when presenting calculator results outside the site, so a score or pass/fail result carries the current cutoff or threshold context.
- The endpoint does not replace government decision makers and does not predict future invitations or case outcomes.
Returns object · 3 example matches; POST responses return up to 12 ranked routes
Agent-facing deterministic route matching over indexable Visa Atlas routes. POST a profile and receive ranked candidate routes with reasons, canonical pages, official source URLs, review dates and legal-scope caveats.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Route-finder contract version. |
| method | string | POST for profile matching; GET returns this contract and an example response. |
| legalNote | string | Explicit informational-only and not-legal-advice caveat. |
| methodology[] | array<string> | Deterministic scoring limits and provenance rules. |
| sourceDatasets[] | array<string> | Public datasets backing route facts and source trails. |
| input.professionSlug | string? | Optional profession taxonomy slug such as software-engineer or nurse. |
| input.nationalityIso | string? | Optional nationality ISO code used for bilateral or nationality-gated route checks. |
| input.targetDestinations[] | array<object>? | Normalized public indexable destination filters. |
| input.sponsorshipAvailable | yes | no | unsure? | Whether the user has employer or sponsor backing. |
| input.needsSettlement | boolean? | Whether permanent residence or settlement matters. |
| input.hasHigherEducation | boolean? | Whether the user has higher-education evidence. |
| input.hasLanguageB2 | boolean? | Whether the user has B2-level language evidence. |
| input.capitalBand | string? | Coarse capital band for investor and entrepreneur scoring. |
| input.ageBand | string? | Broad age band used for youth-mobility and points-route scoring. |
| input.salaryBand | string? | Broad salary band used only as a planning signal. |
| input.dependants | number? | Number of dependants, clamped by the request schema to 0-10. |
| input.routeIntent | string? | Primary intent such as work, study, remote-work or invest. |
| warnings[] | array<string> | Unknown profession, nationality or destination inputs that were ignored. |
| results[] | array<object> | Ranked route candidates. |
| results[].score | number | Deterministic score for ordering; not an official eligibility score. |
| results[].reasons[] | array<string> | Human-readable score reasons. |
| results[].canonicalUrl | string | Canonical Visa Atlas route page. |
| results[].route | object | Destination, route slug, name, category, sponsorship, settlement, summary and last-reviewed date. |
| results[].sources[] | array<object> | Official route sources with labels, URLs, authorities and verification dates. |
| results[].sourceUrls[] | array<string> | Deduplicated official source URLs. |
Example response
POST https://visaatlas.org/api/public/route-finder
{
"professionSlug": "software-engineer",
"nationalityIso": "in",
"targetDestinations": [
"uk",
"germany",
"canada"
],
"sponsorshipAvailable": "yes",
"needsSettlement": true,
"hasHigherEducation": true,
"hasLanguageB2": true,
"ageBand": "30-44",
"salaryBand": "60k-90k",
"dependants": 1,
"routeIntent": "work",
"limit": 3
}
{
"version": "2026-07-03",
"name": "Visa Atlas route finder",
"legalNote": "Informational route matching only, not legal advice or an eligibility decision. Confirm the returned route against the linked government source and, where needed, a qualified immigration adviser.",
"returned": 3,
"results": [
{
"rank": 1,
"score": 88,
"canonicalUrl": "https://visaatlas.org/visas/germany/eu-blue-card",
"route": {
"destinationName": "Federal Republic of Germany",
"visaName": "EU Blue Card (Germany)",
"lastReviewed": "2026-07-08"
},
"sourceUrls": ["https://www.make-it-in-germany.com/en/visa-residence/types/eu-blue-card","https://www.auswaertiges-amt.de/en/visa-service/buergerservice/faq/02a-what-is-the-blue-card/606754"]
}
]
}- This is an API/tool contract, not a static downloadable dataset, so it is documented here and on /ai-agents rather than listed as a Dataset in /api/public.
- Scores are ordering hints from deterministic site data and do not replace route eligibility rules or government decisions.
- GET /api/public/route-finder returns the contract and example; POST returns a profile-specific response.
Returns object · 9 metrics across 5 cohorts
Public measurement contract separating Google organic growth, AI citation share, crawler access, source freshness, open-data discoverability, index quality, rendered SEO gates and competitor-wedge proof. It defines evidence surfaces and commands without exposing private analytics.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Contract version date. |
| name | string | Human contract name. |
| description | string | What the measurement contract covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| trafficModel | object | Planning target and range; not a current traffic claim. |
| count | number | Number of KPI definitions. |
| cohortCount | number | Number of page cohorts tracked. |
| metrics[] | array<object> | One visibility metric per row. |
| metrics[].id | string | Stable metric ID. |
| metrics[].label | string | Human metric label. |
| metrics[].category | string | seo, geo, trust or technical. |
| metrics[].status | string | instrumented, partially-instrumented or roadmap. |
| metrics[].target | string | Measurement target or control objective. |
| metrics[].whyItMatters | string | Reason this KPI matters for SEO/GEO dominance. |
| metrics[].evidenceSurfaces[] | array<string> | Public pages/endpoints supporting the KPI. |
| metrics[].commands[] | array<string> | Local commands that produce or audit the metric where available. |
| metrics[].cadence | string | Recommended measurement cadence. |
| metrics[].caveats[] | array<string> | Limits and interpretation notes. |
| cohorts[] | array<object> | Page cohorts used for reporting and audit grouping. |
| cohorts[].representativePaths[] | array<string> | Representative paths for the cohort. |
| cohorts[].primaryKpis[] | array<string> | Metric IDs most relevant to the cohort. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas SEO/GEO visibility measurement contract",
"trafficModel": {
"planningTargetMonthlyVisits": 500000,
"planningWindow": "24 months",
"note": "This is a planning model, not a current traffic claim."
},
"count": 9,
"cohortCount": 5,
"metrics": [
{
"id": "ai-citation-share",
"category": "geo",
"status": "instrumented",
"target": "At least 40% of fixed benchmark answers cite visaatlas.org.",
"evidenceSurfaces": ["/citation-benchmark", "/api/public/citation-benchmark"],
"commands": ["npm run kpi:citation-share"]
}
]
}- The traffic model is a planning target, not a statement of current sessions or pageviews.
- Private analytics remain private; this endpoint publishes the methodology and public evidence surfaces.
Returns object · 5 forecast cohorts
Falsifiable cohort-level planning model for the Visa Atlas 500k/month SEO/GEO target, tying each traffic range to assumptions, evidence surfaces, measurement commands, dependencies and kill gates.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Forecast model version date. |
| name | string | Human forecast name. |
| description | string | What the forecast model covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets used to ground the cohort assumptions. |
| methodology.planningTargetMonthlyVisits | number | The 500k/month planning target; not current traffic. |
| methodology.planningWindow | string | Planning horizon inherited from the visibility model. |
| methodology.overlapPolicy | string | How cohort ranges are interpreted without double-counting authority lift. |
| methodology.currentTrafficClaim | string | Explicit statement that this forecast publishes no current traffic, ranking, CTR, citation or market-share claim. |
| methodology.privateEvidencePolicy | string | How private sessions, Search Console rows, referrers and experiment outcomes are kept local unless reviewed and aggregated. |
| methodology.caveats[] | array<string> | Limits on interpreting the forecast and triggers for rebasing it. |
| summary.lowMonthlyVisits | number | Low end of the portfolio planning range. |
| summary.highMonthlyVisits | number | High end of the portfolio planning range. |
| summary.planningTargetMonthlyVisits | number | Target monthly visits used by the model. |
| summary.targetWithinRange | boolean | Whether the target sits inside the modeled low/high range. |
| cohorts[] | array<object> | Forecast rows by traffic cohort. |
| cohorts[].targetMonthlyVisits | object | Low/high monthly visit planning range for the cohort. |
| cohorts[].assumptions[] | array<string> | Assumptions that must remain true for the cohort range to hold. |
| cohorts[].evidenceSurfaces[] | array<string> | Public pages and endpoints that ground or audit the cohort. |
| cohorts[].measurementCommands[] | array<string> | Local commands used to measure, audit or rebase the cohort. |
| cohorts[].dependencies[] | array<string> | Operational dependencies that constrain expansion. |
| cohorts[].falsificationGates[] | array<string> | Kill gates that force rebasing or pausing work. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas SEO/GEO traffic forecast model",
"sourceDatasets": ["/api/public/visibility-metrics","/api/public/content-opportunities","/api/public/competitor-query-battlecards"],
"methodology": {
"planningTargetMonthlyVisits": 500000,
"planningWindow": "24 months",
"currentTrafficClaim": "No current traffic, ranking, CTR, AI-citation or market-share claim is published by this forecast."
},
"summary": {
"lowMonthlyVisits": 390000,
"highMonthlyVisits": 600000,
"planningTargetMonthlyVisits": 500000,
"targetWithinRange": true
},
"cohorts": [
{
"id": "calculators-tools",
"targetMonthlyVisits": {"low":90000,"high":140000},
"assumptions": ["High-intent calculator pages retain click demand because users need personal inputs, dated thresholds and route-specific caveats.","Each flagship calculator keeps visible source provenance, deterministic logic and no approval prediction."],
"measurementCommands": ["npm run audit:calculator-provenance","npm run audit:calculator-verdict-contexts"],
"falsificationGates": ["If flagship calculator/tool pages stay below 0.5% CTR at stable rank after the first reviewed GSC experiment window, rebase the cohort target."]
}
]
}- This endpoint is a planning model, not proof of current traffic, rankings, CTR, AI citations or market share.
- Rebase the ranges from reviewed GSC cohorts, AI-citation share, bot-log and authority-distribution evidence rather than from unreviewed anecdotes.
- Private analytics remain local unless converted into separately reviewed aggregate evidence.
Returns object · 9 technical controls
Audit-ready control matrix for the technical SEO/GEO execution behind Visa Atlas: rendering, indexability, schema, API discovery, AI retrieval, freshness, performance and private-evidence boundaries.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Control-matrix version date. |
| name | string | Human dataset name. |
| description | string | What the control matrix covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets and contracts used to ground the controls. |
| methodology.sourceOfTruth | string | How the matrix consolidates existing audits and rendered checks. |
| methodology.cadence | string | When source, rendered, liveness and private-evidence controls should run. |
| methodology.versionInputs | object | Version dates for the source contracts used by the matrix. |
| methodology.privateEvidencePolicy | string | Boundary for analytics, GSC, server logs, snapshots, outreach and reviewer notes. |
| methodology.caveats[] | array<string> | Limits on interpreting controls as outcome claims. |
| summary.controlCount | number | Number of technical controls. |
| summary.criticalCount | number | Number of release-blocking critical controls. |
| summary.commandCount | number | Unique local evidence commands referenced by the matrix. |
| controls[] | array<object> | One technical SEO/GEO control per row. |
| controls[].category | string | rendering, indexability, structured-data, open-data, ai-retrieval, freshness, performance or evidence-governance. |
| controls[].severity | string | critical or high. |
| controls[].auditObjective | string | What the control is intended to prove. |
| controls[].requiredSurfaces[] | array<string> | Public pages, endpoints or local files that must expose the control. |
| controls[].evidenceCommands[] | array<string> | Local commands used to prove the control. |
| controls[].passCriteria[] | array<string> | Conditions that must hold for the control to pass. |
| controls[].failureResponse[] | array<string> | Required response when the control fails. |
| controls[].privateEvidenceBoundary | string | What evidence stays local unless reviewed and aggregated. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas technical SEO/GEO control matrix",
"summary": {
"controlCount": 9,
"criticalCount": 6,
"commandCount": 27
},
"controls": [
{
"id": "release-gate-chain",
"category": "evidence-governance",
"severity": "critical",
"requiredSurfaces": ["/api/public/visibility-metrics","/visibility-metrics","scripts/seo-geo-release-gate.mjs"],
"evidenceCommands": ["npm run audit:seo-geo","npm run audit:release-gate","npm run audit:execution-readiness"],
"passCriteria": ["TypeScript compiles with no emit.","Source/template SEO/GEO audits pass before build."]
}
]
}- This endpoint is a technical control matrix, not proof of rankings, traffic, citations, backlinks or market share.
- Failed critical controls block release or expansion until corrected.
- Private evidence remains local unless converted into separately reviewed aggregate evidence.
Returns object · 12 evidence rows
Big-4-style evidence pack mapping the Visa Atlas SEO/GEO dominance plan to public controls, local evidence workflows, remaining external evidence needs, pass criteria, failure responses and private-data boundaries.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Evidence-pack version date. |
| name | string | Human dataset name. |
| description | string | What the evidence pack covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets and contracts used to ground the evidence rows. |
| methodology.sourceOfTruth | string | How rows consolidate public controls, local commands and private-evidence policies. |
| methodology.completionStandard | string | Why the pack proves control readiness but not the 500k/month outcome. |
| methodology.signoffRules[] | array<string> | Rules for public-control, local-workflow and external-evidence rows. |
| methodology.versionInputs | object | Version dates for source contracts used by the pack. |
| methodology.privateEvidencePolicy | string | Boundary for analytics, GSC, server logs, AI transcripts, outreach and reviewer evidence. |
| methodology.caveats[] | array<string> | Limits on interpreting controls as outcome claims. |
| summary.rowCount | number | Number of evidence rows. |
| summary.statusCounts | object | Evidence rows grouped by proved-public-control, local-workflow and external-evidence-needed. |
| summary.publicEvidenceCount | number | Unique public evidence URLs referenced by rows. |
| summary.sourceDatasetCount | number | Unique source datasets referenced by rows. |
| summary.commandCount | number | Unique local evidence commands referenced by rows. |
| summary.externalEvidenceNeededCount | number | Rows that still need external or private reviewed evidence before claims can be made. |
| summary.evidenceIntakeWorkflowCount | number | Reviewed aggregate evidence intake workflows. |
| evidenceIntake | object | Manifest of reviewed aggregate evidence files, proof commands and claim gates. |
| evidenceIntake.workflows[] | array<object> | One intake workflow per local proof artifact. |
| evidenceIntake.workflows[].inputArtifact | string | Reviewed aggregate file expected by the proof command. |
| evidenceIntake.workflows[].requiredApprovalFields[] | array<string> | Approval fields required before the artifact can support a claim. |
| evidenceIntake.workflows[].forbiddenRawFields[] | array<string> | Raw private fields that must not appear in reviewed aggregate files. |
| evidenceIntake.workflows[].downstreamGate | string | Claim or proof gate the workflow feeds. |
| rows[] | array<object> | One audit evidence row per SEO/GEO domain. |
| rows[].domain | string | strategy, source-quality, technical-seo, ai-retrieval, content, competitor, measurement, authority, ymyl-trust or governance. |
| rows[].status | string | proved-public-control, local-workflow or external-evidence-needed. |
| rows[].auditQuestion | string | Question the row is designed to answer. |
| rows[].publicEvidence[] | array<string> | Public pages and endpoints a reviewer can inspect. |
| rows[].sourceDatasets[] | array<string> | Public JSON feeds grounding the row. |
| rows[].localCommands[] | array<string> | Local commands used to prove the row. |
| rows[].requiredPrivateEvidence[] | array<string> | Evidence that must stay local until reviewed and aggregated. |
| rows[].passCriteria[] | array<string> | Conditions required for the row to pass. |
| rows[].failureResponse[] | array<string> | Required response when the row fails. |
| rows[].privateEvidenceBoundary | string | Explicit private-data boundary for the row. |
Example response
{
"version": "2026-07-05",
"name": "Visa Atlas SEO/GEO audit evidence pack",
"summary": {
"rowCount": 12,
"statusCounts": {"proved-public-control":6,"local-workflow":3,"external-evidence-needed":3},
"externalEvidenceNeededCount": 3,
"commandCount": 69,
"evidenceIntakeWorkflowCount": 9
},
"evidenceIntake": {
"workflowCount": 9,
"workflows": [
{
"id": "production-ticket-evidence",
"inputArtifact": "seo-geo-ticket-evidence.jsonl",
"proofCommand": "npm run seo:ticket-evidence -- seo-geo-ticket-evidence.jsonl --json"
}
]
},
"rows": [
{
"id": "strategy-and-traffic-model",
"status": "proved-public-control",
"publicEvidence": ["/research/seo-geo-traffic-forecast-2026","/api/public/traffic-forecast","/visibility-metrics"],
"localCommands": ["npm run audit:traffic-forecast","npm run audit:visibility-metrics"],
"privateEvidenceBoundary": "Actual sessions, Search Console rows, AI-citation runs and referrer exports stay local unless reviewed and aggregated."
}
]
}- This endpoint is an audit evidence matrix, not proof of current traffic, rankings, citations, backlinks or market share.
- External-evidence-needed rows cannot be used as outcome claims until reviewed private or external evidence is approved.
- The 500k/month objective remains unproven until reviewed analytics, Search Console, AI-citation and market-share evidence prove it.
Returns object · 5 readiness cohorts
Cohort-level execution scorecard tying the Visa Atlas 500k/month SEO/GEO plan to content pieces, page changes, technical gates, competitor wedges, private evidence needs, no-go conditions and pass criteria.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Scorecard version date. |
| name | string | Human dataset name. |
| description | string | What the scorecard covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets and contracts used to compile readiness rows. |
| methodology.planningTargetMonthlyVisits | number | The 500k/month planning target; not current traffic. |
| methodology.sourceOfTruth | string | Public contracts used as the source of truth. |
| methodology.completionStandard | string | Why the scorecard proves readiness but not outcome success. |
| methodology.privateEvidencePolicy | string | Boundary for analytics, GSC, AI outputs, SERP screenshots, logs and outreach records. |
| methodology.versionInputs | object | Version dates for source contracts used by the scorecard. |
| summary.cohortCount | number | Number of forecast cohorts covered. |
| summary.statusCounts | object | Readiness rows grouped by control-ready, controlled-build and external-evidence-needed. |
| summary.lowMonthlyVisits | number | Low end of the cohort planning range. |
| summary.highMonthlyVisits | number | High end of the cohort planning range. |
| summary.commandCount | number | Unique local commands required across rows. |
| summary.externalEvidenceNeededCount | number | Cohorts where external or private reviewed evidence gates outcome claims. |
| rows[] | array<object> | One readiness row per traffic forecast cohort. |
| rows[].status | string | control-ready, controlled-build or external-evidence-needed. |
| rows[].targetMonthlyVisits | object | Low/high planning range from the traffic forecast. |
| rows[].launchDecision | string | Operational decision for scaling or gating the cohort. |
| rows[].contentPiecesNeeded[] | array<string> | Content pieces or evidence assets required for the cohort. |
| rows[].pageChangesNeeded[] | array<string> | Page-level changes required before scale. |
| rows[].technicalChangesNeeded[] | array<string> | Technical gates or implementation changes required. |
| rows[].competitorWedge | string | How the cohort should beat sampled competitor source classes. |
| rows[].relatedOpportunityIds[] | array<string> | Content opportunity rows connected to the cohort. |
| rows[].relatedBattlecardIds[] | array<string> | Competitor battlecards connected to the cohort. |
| rows[].relatedSearchDemandActionIds[] | array<string> | Search-demand action rules connected to the cohort. |
| rows[].requiredLocalCommands[] | array<string> | Local commands required for readiness and measurement. |
| rows[].requiredPrivateEvidence[] | array<string> | Private or external evidence required before outcome claims. |
| rows[].noGoConditions[] | array<string> | Conditions that block scale, publication or outcome claims. |
| rows[].passCriteria[] | array<string> | Conditions required for the cohort to pass review. |
| rows[].privateEvidenceBoundary | string | What evidence stays local unless reviewed and aggregated. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas SEO/GEO execution readiness scorecard",
"summary": {
"cohortCount": 5,
"statusCounts": {"control-ready":3,"controlled-build":1,"external-evidence-needed":1},
"lowMonthlyVisits": 390000,
"highMonthlyVisits": 600000,
"commandCount": 28
},
"rows": [
{
"id": "calculators-tools",
"status": "control-ready",
"targetMonthlyVisits": {"low":90000,"high":140000},
"relatedOpportunityIds": ["calculator-verdict-history","uk-total-migration-cost-builder","germany-recognition-decision-tree"],
"relatedBattlecardIds": ["uk-skilled-worker-cost-salary","canada-express-entry-freshness","germany-blue-card-salary-recognition"],
"noGoConditions": ["If flagship calculator/tool pages stay below 0.5% CTR at stable rank after the first reviewed GSC experiment window, rebase the cohort target.","If calculator audits fail or source freshness goes red, freeze new calculator launches until provenance is restored."]
}
]
}- This endpoint is a readiness scorecard, not proof of current traffic, rankings, citations, backlinks or market share.
- Control-ready rows still require reviewed GSC, AI-citation, analytics or external evidence before outcome claims.
- Use it with /api/public/search-demand-actions when deciding whether to edit, route, noindex or measure a cohort.
Returns object · 52 production tickets
Flat ticket queue derived from the market-share capture plan. Use it when an editor, engineer, growth owner or AI agent needs the next executable content, page, technical or evidence task without traversing nested battlecard rows.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Production-queue version date inherited from the capture plan. |
| name | string | Human dataset name. |
| description | string | What the queue covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the queue. |
| humanUrl | string | Crawlable report page for the queue. |
| sourceDatasets[] | array<string> | Public contracts used to derive and audit the queue. |
| methodology.sourceOfTruth | string | How tickets are derived from /api/public/market-share-capture-plan. |
| methodology.completionStandard | string | Why ticket completion does not prove rankings, traffic, citations, backlinks, market share or 500k/month outcomes. |
| methodology.privateEvidencePolicy | string | Boundary for raw analytics, GSC, SERP, AI-answer and reviewer evidence. |
| summary.ticketCount | number | Number of flat production tickets. |
| summary.readyToExecuteCount | number | Tickets where public control surfaces exist for execution. |
| summary.evidenceGatedCount | number | Tickets blocked by reviewed evidence needs before public progress claims. |
| summary.workstreamCounts | object | Ticket counts by content, page, technical and evidence workstream. |
| summary.ownerFunctionCounts | object | Ticket counts by Editorial, Growth, Engineering and Data/research owner. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved aggregate evidence exists. |
| tickets[] | array<object> | One flat production ticket per content/page/technical/evidence task. |
| tickets[].parentRowId | string | Source market-share capture-plan row ID. |
| tickets[].parentTitle | string | Source market-share capture-plan row title. |
| tickets[].battlecardId | string | Source competitor battlecard ID. |
| tickets[].workstream | string | content, page, technical or evidence. |
| tickets[].ownerFunction | string | Editorial, Growth, Engineering or Data/research. |
| tickets[].targetPages[] | array<string> | Pages the ticket touches. |
| tickets[].task | string | Human production task. |
| tickets[].dependencies[] | array<string> | Prerequisites before the ticket can be treated as done. |
| tickets[].localCommands[] | array<string> | Local evidence commands for verification. |
| tickets[].sourceDatasets[] | array<string> | Public datasets that audit the ticket. |
| tickets[].evidenceGate | string | Gate that must pass before the ticket can support progress claims. |
| tickets[].noGoCondition | string | Condition that blocks publication, scale or outcome claims. |
| tickets[].definitionOfDone | string | Audit-ready done condition for the ticket. |
| tickets[].marketShareClaimGate | string | Parent battlecard claim gate before market-share statements. |
| tickets[].privateEvidenceBoundary | string | What evidence stays local unless reviewed and aggregated. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas SEO/GEO production queue",
"summary": {
"ticketCount": 52,
"workstreamCounts": {"content":13,"page":13,"technical":13,"evidence":13},
"ownerFunctionCounts": {"Editorial":13,"Engineering":13,"Data/research":13,"Growth":13},
"publicMarketShareClaimAllowed": false
},
"tickets": [
{
"id": "uk-skilled-worker-cost-salary-content-production",
"parentRowId": "uk-skilled-worker-cost-salary-capture-plan",
"battlecardId": "uk-skilled-worker-cost-salary",
"workstream": "content",
"ownerFunction": "Editorial",
"targetPages": ["/salary-thresholds/uk","/visas/uk/skilled-worker","/calculators/uk-skilled-worker"],
"evidenceGate": "All short-answer, methodology, caveat and citation-pack copy must render in static HTML with source dates before release.",
"definitionOfDone": "Target pages expose the answer shape, source-backed facts, caveats, citation surfaces and internal links required by the battlecard."
}
]
}- This endpoint is a production queue, not proof of current rankings, traffic, citations, backlinks or market share.
- Every ticket keeps parent battlecard context so AI agents can cite the source row and its private-evidence boundary.
- Use it with /api/public/market-share-capture-plan when deciding which ticket to execute next.
Returns object · 118 target URLs
Page-level join table derived from the production queue. Use it when an agent or auditor needs to know which target URL connects to which production tickets, battlecards, SERP/AI handoff briefs, search-demand actions, answer capsules, citation packs, calculator contexts, source datasets, commands and evidence gates.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Page-action-map version date inherited from the production queue. |
| name | string | Human dataset name. |
| description | string | What the map covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the page action map. |
| humanUrl | string | Crawlable report page for the map. |
| sourceDatasets[] | array<string> | Public contracts used to derive and audit the map. |
| methodology.sourceOfTruth | string | How rows are derived from /api/public/seo-geo-production-queue and related datasets. |
| methodology.joinRules[] | array<string> | Exact join rules for tickets, answer capsules, citation packs, calculator contexts and search-demand actions. |
| methodology.completionStandard | string | Why page-action coverage does not prove rankings, traffic, citations, backlinks, market share or 500k/month outcomes. |
| methodology.privateEvidencePolicy | string | Boundary for raw analytics, GSC, SERP, AI-answer and reviewer evidence. |
| summary.pageCount | number | Number of target URLs in the map. |
| summary.productionTicketReferenceCount | number | Total production-ticket references across page rows. |
| summary.rowsWithAnswerCapsules | number | Target URL rows joined to answer capsules. |
| summary.rowsWithCitationPacks | number | Target URL rows joined to citation packs. |
| summary.rowsWithCalculatorContexts | number | Target URL rows joined to calculator verdict contexts. |
| summary.rowsWithSerpAiHandoffs | number | Target URL rows with generated SERP/AI handoff briefs. |
| summary.rowsNeedingAnswerSurface | number | Target URL rows that still need an answer capsule, citation pack or calculator context before they are answer-ready. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved aggregate evidence exists. |
| rows[] | array<object> | One target URL with retrieval joins and production-control gates. |
| rows[].path | string | Target URL path, including fragment when relevant. |
| rows[].basePath | string | Target URL without fragment. |
| rows[].coverageStatus | string | sitemap-backed, fragment-on-sitemap-page or missing. |
| rows[].battlecardIds[] | array<string> | Competitor battlecards connected to the page. |
| rows[].productionTickets[] | array<object> | Content, page, technical and evidence tickets for the page. |
| rows[].searchDemandActions[] | array<object> | Search-demand action rules inherited from related tickets. |
| rows[].serpAiHandoff | object | SERP title/meta/first-answer and AI retrieval handoff brief generated from the page battlecards and retrieval joins. |
| rows[].serpAiHandoff.titleSnippetRule | string | Page-specific rule for leading the title, meta description and first visible answer. |
| rows[].serpAiHandoff.answerSurfaceStatus | string | answer-capsule, citation-pack, calculator-context or needs-page-answer. |
| rows[].serpAiHandoff.retrievalSurfaceUrls[] | array<string> | Canonical target, answer, citation and calculator surfaces available to retrievers. |
| rows[].serpAiHandoff.noGoBoundary | string | Publication or outcome-claim blocker for the handoff. |
| rows[].answerCapsules[] | array<object> | Verified answer capsules joined to the page. |
| rows[].citationPacks[] | array<object> | Citation packs joined by canonical page or citation-pack fragment. |
| rows[].calculatorContexts[] | array<object> | Calculator verdict contexts joined by calculatorPath. |
| rows[].localCommands[] | array<string> | Local evidence commands for the page row. |
| rows[].evidenceGates[] | array<string> | Gates that must pass before the page can support progress claims. |
| rows[].noGoConditions[] | array<string> | Conditions that block publication, scale or outcome claims. |
| rows[].definitionsOfDone[] | array<string> | Audit-ready done conditions for linked tickets. |
| rows[].marketShareClaimGates[] | array<string> | Claim gates inherited from parent battlecards. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas SEO/GEO page action map",
"summary": {
"pageCount": 118,
"productionTicketReferenceCount": 496,
"rowsWithAnswerCapsules": 115,
"rowsWithCalculatorContexts": 9,
"rowsWithSerpAiHandoffs": 118,
"rowsNeedingAnswerSurface": 0,
"publicMarketShareClaimAllowed": false
},
"rows": [
{
"path": "/salary-thresholds/uk",
"battlecardIds": ["uk-skilled-worker-cost-salary"],
"serpAiHandoff": {"primaryIntent":"cost","queryCluster":["UK Skilled Worker visa cost including IHS","UK Skilled Worker minimum salary 2026","Health and Care Worker IHS exemption"],"titleSnippetRule":"Lead the title, meta description and first visible answer with the cost answer for \"UK Skilled Worker visa cost including IHS\", then show the source date and canonical dataset link before broader guidance.","firstAnswerSource":"answer-capsule:salary-uk - What salary do you need for a skilled-work visa in United Kingdom?","answerSurfaceStatus":"answer-capsule","retrievalSurfaceUrls":["/salary-thresholds/uk","https://visaatlas.org/answer-capsules#salary-uk","https://visaatlas.org/salary-thresholds/uk","/api/public/answer-capsules","https://visaatlas.org/citation-packs#answer-capsule-salary-uk","/api/public/citation-packs"],"competitorWedge":"Separate money paid away from money shown, then connect the route cost, salary floor, IHS exemption and ILR timing in one source-backed answer path.","auditGate":"Run rendered SEO, answer-capsule/citation-pack or calculator-context audits, then require reviewed GSC or AI-citation evidence before claiming displacement.","noGoBoundary":"Do not claim rankings, traffic, AI citation share or market-share gains from this handoff without approved aggregate evidence."},
"productionTickets": [{"id":"uk-skilled-worker-cost-salary-content-production","title":"UK Skilled Worker cost, IHS and salary floors capture plan: content production","battlecardId":"uk-skilled-worker-cost-salary","parentRowId":"uk-skilled-worker-cost-salary-capture-plan","workstream":"content","ownerFunction":"Editorial","status":"ready-to-execute","runOrder":11,"priority":"high","task":"Battlecard answer shape: Table answer: application fee, IHS, maintenance/proof-of-funds, salary floor, ILR timing, source dates and calculator links. Single first-answer block separating application fee, IHS, maintenance, salary floor and settlement timing. Worked family-cost example that distinguishes money paid away from refundable or show-only funds. Citation-pack row for the UK Skilled Worker cost and salary answer used by AI retrievers.","evidenceGate":"All short-answer, methodology, caveat and citation-pack copy must render in static HTML with source dates before release.","noGoCondition":"Do not merge IHS-exempt and non-exempt routes into one cost claim.","definitionOfDone":"Target pages expose the answer shape, source-backed facts, caveats, citation surfaces and internal links required by the battlecard."},{"id":"uk-skilled-worker-cost-salary-page-production","title":"UK Skilled Worker cost, IHS and salary floors capture plan: page and crawl-path production","battlecardId":"uk-skilled-worker-cost-salary","parentRowId":"uk-skilled-worker-cost-salary-capture-plan","workstream":"page","ownerFunction":"Growth","status":"ready-to-execute","runOrder":12,"priority":"high","task":"Tighten /calculators/uk-total-migration-cost, /cost-to-complete/uk-skilled-worker and /salary-thresholds/uk around the same short answer. Add above-the-fold links from UK Skilled Worker route pages to the total-cost builder, fee page and salary page. Keep Health and Care Worker IHS exemption context visible where the query intent would otherwise collapse routes. Add or verify contextual internal link to /salary-thresholds/uk. Add or verify contextual internal link to /visas/uk/skilled-worker. Add or verify contextual internal link to /calculators/uk-skilled-worker. Add or verify contextual internal link to /cost-to-complete/uk-skilled-worker. Add or verify contextual internal link to /fees/uk/skilled-worker. Add or verify contextual internal link to /calculators/visa-fees.","evidenceGate":"Canonical target pages, internal links, indexability intent and crawl-path entry points must be visible in sitemap-backed rendered artifacts.","noGoCondition":"Do not publish a cost winner claim without source-linked current figures.","definitionOfDone":"Target pages are linked from the correct hubs, sitemap/indexable-page intent is coherent, and unsupported variants remain excluded."}],
"answerCapsules": ["salary-uk"],
"localCommands": ["npm run audit:content-opportunities","npm run audit:answer-capsules"]
}
]
}- This endpoint is relationship metadata, not proof of current rankings, traffic, citations, backlinks or market share.
- Rows without answer capsules can still be valid when the related workstream is page, technical or evidence.
- Use it with /api/public/seo-geo-production-queue when selecting the next target URL to edit or audit.
Returns object · 13 battlecard rows
Battlecard-level SEO/GEO coverage matrix joining competitor query clusters to target pages, page-action rows, answer surfaces, citation packs, AI retrieval prompts, experiments, snapshot protocols, quarterly baselines and evidence gates. It reconciles public retrieval readiness without claiming rankings, traffic, AI citations or market share.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Coverage-matrix version date. |
| name | string | Human dataset name. |
| description | string | What the matrix covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the matrix. |
| humanUrl | string | Crawlable report page explaining the join and scoring rules. |
| sourceDatasets[] | array<string> | Public datasets used to derive and audit the matrix. |
| methodology.sourceOfTruth | string | How battlecards join to page actions, AI prompts and measurement contracts. |
| methodology.joinRules[] | array<string> | Exact battlecardId, page-action and task-index join rules. |
| methodology.scoringModel[] | array<string> | Weights for page-action, citation-pack, answer-surface, AI-task, measurement and claim-gate checks. |
| methodology.privateEvidencePolicy | string | Boundary for analytics, Search Console, SERP, AI-answer and reviewer evidence. |
| summary.battlecardCount | number | Number of competitor battlecards covered. |
| summary.publicRetrievalReadyCount | number | Rows with complete public retrieval coverage and no external-evidence status. |
| summary.externalEvidenceNeededCount | number | Rows with complete retrieval assets but external or aggregate evidence still required. |
| summary.assetGapCount | number | Rows below the retrieval coverage threshold. |
| summary.pageActionRowsWithCitationPacks | number | Page-action rows joined to citation packs. |
| summary.openAiRetrievalGapCount | number | AI retrieval readiness rows below retrieval-ready. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved aggregate evidence exists. |
| rows[] | array<object> | One coverage row per competitor query battlecard. |
| rows[].battlecardId | string | Source competitor query battlecard ID. |
| rows[].coverageStatus | string | public-retrieval-ready, external-evidence-needed or asset-gap. |
| rows[].coverageScore | number | Weighted public retrieval coverage score from 0 to 100. |
| rows[].retrievalSurfaceIds | object | Joined answer capsule, citation pack, calculator context and MCP tool IDs. |
| rows[].measurementSurfaceIds | object | Joined experiment, snapshot protocol and quarterly baseline IDs. |
| rows[].coverage | object | Counts for target pages, page actions, answer/citation/calculator joins, AI prompts, tickets, actions, datasets and commands. |
| rows[].checks[] | array<object> | Weighted pass/fail checks and remediation. |
| rows[].nextActions[] | array<string> | What must happen next before measurement or outcome claims. |
| rows[].privateEvidenceBoundary | string | What evidence stays local unless reviewed and aggregated. |
Example response
{
"version": "2026-07-06",
"name": "Visa Atlas battlecard retrieval coverage matrix",
"datasetUrl": "/api/public/battlecard-retrieval-coverage",
"humanUrl": "/research/battlecard-retrieval-coverage-matrix-2026",
"summary": {
"battlecardCount": 13,
"publicRetrievalReadyCount": 11,
"externalEvidenceNeededCount": 2,
"assetGapCount": 0,
"pageActionRowsWithCitationPacks": 118,
"openAiRetrievalGapCount": 0,
"publicMarketShareClaimAllowed": false
},
"rows": [
{
"battlecardId": "germany-blue-card-salary-recognition",
"coverageStatus": "public-retrieval-ready",
"coverageScore": 100,
"coverage": {"targetPageCount":8,"pageActionRowCount":8,"readyToExecutePageCount":8,"evidenceGatedPageCount":0,"pagesWithAnswerCapsules":8,"pagesWithCitationPacks":8,"pagesWithCalculatorContexts":1,"pagesWithSerpAiHandoffs":8,"pagesNeedingAnswerSurface":0,"aiRetrievalTaskCount":3,"highPriorityAiRetrievalTaskCount":3,"retrievalReadyTaskCount":3,"openAiRetrievalGapCount":0,"productionTicketCount":44,"searchDemandActionCount":6,"citationQuestionCount":3,"sourceDatasetCount":37,"commandCount":27},
"measurementSurfaceIds": {"experimentIds":["germany-blue-card-salary-recognition-gsc-experiment"],"snapshotProtocolIds":["germany-blue-card-salary-recognition-surface-snapshot"],"quarterlyBaselineIds":["germany-blue-card-salary-recognition-market-share-baseline"]}
}
]
}- Use this endpoint after /api/public/seo-geo-page-action-map when deciding whether a whole battlecard cluster is retrieval-ready.
- Rows marked external-evidence-needed have public retrieval assets but still require approved external or aggregate evidence before outcome claims.
- This endpoint does not prove rankings, traffic, backlinks, AI citation share, market share or the 500k/month planning target.
Returns object · 13 battlecard rows
Battlecard-level blocker ledger joining public retrieval coverage, content pieces, page changes, technical work, competitor pressure, reviewer queues, authority distribution and outcome-proof gates for the 500k/month SEO/GEO plan.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Ledger version date. |
| name | string | Human dataset name. |
| description | string | What the ledger covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the ledger. |
| humanUrl | string | Crawlable report page explaining joins, blockers and evidence limits. |
| sourceDatasets[] | array<string> | Public datasets used to derive and audit the ledger. |
| methodology.joinRules[] | array<string> | Battlecard, reviewer, authority and outcome-proof join rules. |
| methodology.blockerModel[] | array<string> | Meaning of each dominance gap status. |
| summary.readyForPrivateMeasurementCount | number | Rows whose public controls are ready for private measurement workflows. |
| summary.reviewerEvidenceNeededCount | number | Rows joined to high-risk reviewer queues. |
| summary.externalEvidenceNeededCount | number | Rows blocked by external or approved aggregate evidence. |
| summary.approvedSnapshotCount | number | Approved live SERP/AI market-share snapshots currently published. |
| summary.publicTrafficOutcomeClaimAllowed | boolean | Always false until reviewed outcome proof exists. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved market-share proof exists. |
| rows[] | array<object> | One blocker row per competitor query battlecard. |
| rows[].dominanceGapStatus | string | ready-for-private-measurement, reviewer-evidence-needed, external-evidence-needed or public-asset-gap. |
| rows[].contentPiecesNeeded[] | array<string> | Battlecard-level content pieces required by the capture plan. |
| rows[].pageChangesNeeded[] | array<string> | Page and crawl-path changes required by the capture plan. |
| rows[].technicalChangesNeeded[] | array<string> | Technical changes and audit gates required by the battlecard. |
| rows[].reviewerQueues[] | array<object> | Joined reviewer queues for high-risk YMYL page targets. |
| rows[].outcomeProofNeeded[] | array<string> | Evidence required before traffic, market-share or 500k/month claims. |
| rows[].noGoBoundaries[] | array<string> | Claims that must remain blocked without reviewed evidence. |
Example response
{
"version": "2026-07-06",
"name": "Visa Atlas SEO/GEO dominance gap ledger",
"datasetUrl": "/api/public/seo-geo-dominance-gap-ledger",
"humanUrl": "/research/seo-geo-dominance-gap-ledger-2026",
"summary": {
"battlecardCount": 13,
"readyForPrivateMeasurementCount": 3,
"reviewerEvidenceNeededCount": 8,
"externalEvidenceNeededCount": 2,
"approvedSnapshotCount": 0,
"publicTrafficOutcomeClaimAllowed": false,
"publicMarketShareClaimAllowed": false
},
"rows": [
{
"battlecardId": "uk-skilled-worker-cost-salary",
"dominanceGapStatus": "reviewer-evidence-needed",
"publicRetrievalCoverage": {"coverageScore":100,"pageActionRowCount":11,"aiRetrievalTaskCount":4,"openAiRetrievalGapCount":0,"experimentCount":1,"snapshotProtocolCount":1,"quarterlyBaselineCount":1},
"reviewerQueues": [{"id":"uk-skilled-worker-yml-review","title":"UK Skilled Worker eligibility, salary and total-cost review","priority":"p0","status":"awaiting-credentialed-review","pageTargets":["/visas/uk/skilled-worker","/calculators/uk-skilled-worker","/calculators/uk-total-migration-cost","/cost-to-complete/uk-skilled-worker"]}]
}
]
}- Use this endpoint after retrieval coverage when deciding which blocker prevents a battlecard from supporting dominance claims.
- ready-for-private-measurement is not an outcome claim; it means the public controls are ready for private GSC, SERP, AI and analytics evidence workflows.
- This endpoint does not prove rankings, traffic, AI citations, backlinks, market share or the 500k/month target.
Returns object · 13 measurement runs
Battlecard-level measurement run queue that turns dominance blockers into private GSC, SERP/AI, reviewer, authority, AI-visibility, market-share and traffic-outcome evidence runs without publishing raw private evidence.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Queue version date. |
| name | string | Human dataset name. |
| description | string | What the queue covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the queue. |
| humanUrl | string | Crawlable report page explaining run classes and evidence limits. |
| sourceDatasets[] | array<string> | Public datasets used to derive and audit the queue. |
| methodology.runOrderRules[] | array<string> | How public controls, reviewer proof, external evidence and final gates are ordered. |
| methodology.publicationGates[] | array<string> | Commands and approval flags required before public outcome claims. |
| summary.runCount | number | Number of battlecard measurement runs. |
| summary.runNowPhaseCount | number | Runnable phases before blocker resolution. |
| summary.finalOutcomeGateCount | number | Final AI visibility and traffic outcome gates. |
| summary.priorityActionCount | number | Runnable private-evidence actions after excluding public-control and final outcome gates. |
| summary.publicTrafficOutcomeClaimAllowed | boolean | Always false until reviewed traffic proof exists. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved market-share proof exists. |
| priorityBrief | object | Ranked next-action brief for private-evidence execution. |
| priorityBrief.topActions[] | array<object> | Top runnable reviewer, authority, GSC, SERP/AI and market-share actions. |
| priorityBrief.topActions[].commands[] | array<string> | Local commands to run for the action. |
| priorityBrief.noGoPolicy | string | Why priority actions do not permit public outcome claims. |
| rows[] | array<object> | One measurement run per competitor query battlecard. |
| rows[].measurementStatus | string | ready-for-private-measurement, reviewer-evidence-blocked, external-evidence-blocked or public-asset-blocked. |
| rows[].firstRunnablePhaseIds[] | array<string> | Phase IDs that can run before resolving the current blocker. |
| rows[].blockedBy[] | array<string> | Current blocker labels, if any. |
| rows[].phases[] | array<object> | Public-control, reviewer, authority, GSC, SERP/AI, market-share, AI visibility and traffic proof phases. |
| rows[].phases[].runClass | string | run-now, run-after-reviewer-evidence, run-after-external-evidence, run-after-public-assets or final-outcome-gate. |
| rows[].localCommands[] | array<string> | Local commands needed to collect, review or audit evidence. |
| rows[].privateEvidenceBoundary | string | What raw evidence stays local unless reviewed, redacted and aggregated. |
Example response
{
"version": "2026-07-06",
"name": "Visa Atlas SEO/GEO measurement run queue",
"datasetUrl": "/api/public/seo-geo-measurement-run-queue",
"humanUrl": "/research/seo-geo-measurement-run-queue-2026",
"summary": {
"runCount": 13,
"runNowPhaseCount": 39,
"reviewerEvidenceBlockedCount": 8,
"externalEvidenceBlockedCount": 2,
"finalOutcomeGateCount": 26,
"priorityActionCount": 26,
"publicTrafficOutcomeClaimAllowed": false,
"publicMarketShareClaimAllowed": false
},
"priorityBrief": {
"actionCount": 26,
"topActionCount": 12,
"topActions": [
{
"rank": 1,
"battlecardId": "uk-skilled-worker-cost-salary",
"phaseId": "reviewer-proof",
"runClass": "run-now"
}
]
},
"rows": [
{
"battlecardId": "uk-skilled-worker-cost-salary",
"measurementStatus": "reviewer-evidence-blocked",
"firstRunnablePhaseIds": ["public-control-check","reviewer-proof"],
"blockedBy": ["reviewer queue: uk-skilled-worker-yml-review"]
}
]
}- Use this endpoint after the dominance gap ledger when deciding which private measurement or proof workflow to run next.
- Run-now phases can still be blocked from public outcome claims until the final approval gates pass.
- This endpoint does not prove rankings, traffic, AI citations, backlinks, reviewer trust, market share or the 500k/month target.
Returns object · 6 reviewer queues and 8 reviewer-blocked battlecards
Public bridge from reviewer-blocked SEO/GEO battlecards to high-risk reviewer queues, acquisition controls, reviewedBy schema gates, P0 page-refresh controls and local reviewer-proof commands.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Bridge version date. |
| name | string | Human dataset name. |
| description | string | What the bridge covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the bridge. |
| humanUrl | string | Crawlable report page explaining reviewer-evidence routing. |
| sourceDatasets[] | array<string> | Public controls used to derive and audit the bridge. |
| methodology.joinRules[] | array<string> | How battlecards, queues, controls and pages are joined. |
| methodology.publicationGates[] | array<string> | Reviewer acquisition, reviewedBy, P0 refresh and proof gates. |
| methodology.noGoPolicy | string | Why the bridge does not permit outcome or trust claims. |
| summary.reviewerBlockedBattlecardCount | number | Reviewer-blocked SEO/GEO battlecards. |
| summary.reviewerQueueCount | number | Reviewer queues blocking those battlecards. |
| summary.p0ReviewerQueueCount | number | P0 reviewer queues with page-refresh controls. |
| summary.publicReviewerTrustClaimAllowed | boolean | Always false until reviewed proof exists. |
| summary.publicReviewedBySchemaClaimAllowed | boolean | Always false until reviewedBy evidence and page-level schema review exist. |
| summary.publicTrafficOutcomeClaimAllowed | boolean | Always false until reviewed traffic proof exists. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved market-share proof exists. |
| reviewerQueues[] | array<object> | One bridge row per reviewer queue that blocks SEO/GEO battlecards. |
| reviewerQueues[].publicationGate.publicReviewerTrustClaimAllowed | boolean | Whether a public reviewer-trust claim is allowed for the queue. |
| reviewerQueues[].publicationGate.publicReviewedBySchemaClaimAllowed | boolean | Whether reviewedBy schema is allowed for the queue. |
| reviewerQueues[].requiredLocalEvidenceFields[] | array<string> | Evidence fields required before reviewer handoff, schema export or page refresh. |
| reviewerQueues[].localCommands[] | array<string> | Local reviewer acquisition, reviewedBy export, P0 refresh and reviewer-proof commands. |
| battlecards[] | array<object> | Reviewer-blocked battlecard rows with queue IDs, runnable phases and no-go conditions. |
| battlecards[].measurementStatus | string | Expected reviewer-evidence-blocked until reviewer evidence exists. |
| pageHandoffs[] | array<object> | Target URL to reviewer queue and battlecard joins. |
| pageHandoffs[].p0ReviewStatusSurface | boolean | Whether the page is covered by the P0 review-status surface. |
Example response
{
"version": "2026-07-07",
"name": "Visa Atlas SEO/GEO reviewer evidence bridge",
"datasetUrl": "/api/public/seo-geo-reviewer-evidence-bridge",
"humanUrl": "/research/seo-geo-reviewer-evidence-bridge-2026",
"summary": {
"reviewerBlockedBattlecardCount": 8,
"reviewerQueueCount": 6,
"p0ReviewerQueueCount": 3,
"publicReviewerTrustClaimAllowed": false,
"publicReviewedBySchemaClaimAllowed": false,
"publicTrafficOutcomeClaimAllowed": false,
"publicMarketShareClaimAllowed": false
},
"reviewerQueues": [
{
"id": "uk-skilled-worker-yml-review-reviewer-evidence-bridge",
"status": "blocked-pending-reviewer-evidence",
"battlecardIds": ["uk-skilled-worker-cost-salary"],
"publicationGate": {
"publicReviewerTrustClaimAllowed": false,
"publicReviewedBySchemaClaimAllowed": false
}
}
],
"pageHandoffs": [
{
"path": "/visas/uk/skilled-worker",
"p0ReviewStatusSurface": true
}
]
}- Use this endpoint after the measurement run queue when a battlecard is reviewer-evidence-blocked.
- The bridge joins public controls and local command requirements; it is not evidence that reviewer trust or reviewedBy schema has been approved.
- Raw reviewer notes, private contacts, credential screenshots, Search Console exports, screenshots, transcripts and analytics stay local unless reviewed, redacted and aggregated.
Returns object · 2 external-evidence battlecards and 6 authority channels
Public bridge from external-evidence-blocked SEO/GEO battlecards to authority distribution channels, GSC/SERP/AI evidence workflows, market-share baselines, traffic proof gates and local proof commands.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Bridge version date. |
| name | string | Human dataset name. |
| description | string | What the bridge covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the bridge. |
| humanUrl | string | Crawlable report page explaining external-evidence routing. |
| sourceDatasets[] | array<string> | Public controls used to derive and audit the bridge. |
| methodology.joinRules[] | array<string> | How battlecards, evidence runs, authority channels, baselines and pages are joined. |
| methodology.publicationGates[] | array<string> | Authority, market-share, AI-visibility and traffic proof gates. |
| methodology.noGoPolicy | string | Why the bridge does not permit outcome or authority claims. |
| summary.externalEvidenceBattlecardCount | number | External-evidence-blocked SEO/GEO battlecards. |
| summary.authorityChannelCount | number | Authority distribution channels tied to the blocked rows. |
| summary.approvedSnapshotCount | number | Approved market-share snapshots currently published; expected 0 until reviewed rollups exist. |
| summary.publicAuthorityClaimAllowed | boolean | Always false until reviewed authority proof exists. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved market-share proof exists. |
| summary.publicAiVisibilityClaimAllowed | boolean | Always false until approved AI visibility proof exists. |
| summary.publicTrafficOutcomeClaimAllowed | boolean | Always false until reviewed traffic proof exists. |
| authorityChannels[] | array<object> | One bridge row per authority channel needed by the external-evidence battlecards. |
| authorityChannels[].publicationGate.publicAuthorityClaimAllowed | boolean | Whether a public authority claim is allowed for the channel. |
| battlecards[] | array<object> | External-evidence-blocked battlecard rows with runnable phases and no-go conditions. |
| battlecards[].measurementStatus | string | Expected external-evidence-blocked until reviewed evidence exists. |
| battlecards[].runNowPhaseIds[] | array<string> | Authority, GSC and SERP/AI phases that can run before outcome claims. |
| battlecards[].publicationGate.publicExternalEvidenceClaimAllowed | boolean | Whether a public external-evidence claim is allowed for the row. |
| pageHandoffs[] | array<object> | Target URL to external-evidence battlecard joins. |
Example response
{
"version": "2026-07-07",
"name": "Visa Atlas SEO/GEO external evidence bridge",
"datasetUrl": "/api/public/seo-geo-external-evidence-bridge",
"humanUrl": "/research/seo-geo-external-evidence-bridge-2026",
"summary": {
"externalEvidenceBattlecardCount": 2,
"authorityChannelCount": 6,
"approvedSnapshotCount": 0,
"publicAuthorityClaimAllowed": false,
"publicMarketShareClaimAllowed": false,
"publicAiVisibilityClaimAllowed": false,
"publicTrafficOutcomeClaimAllowed": false
},
"battlecards": [
{
"id": "digital-nomad-europe-costs-external-evidence-bridge",
"status": "blocked-pending-external-evidence",
"battlecardId": "digital-nomad-europe-costs",
"runNowPhaseIds": ["public-control-check","authority-proof","gsc-experiment","serp-ai-snapshot"]
}
],
"authorityChannels": [
{
"id": "official-mcp-registry-external-evidence-bridge",
"status": "manual-publication-ready",
"publicationGate": {
"publicAuthorityClaimAllowed": false,
"publicBacklinkClaimAllowed": false
}
}
]
}- Use this endpoint after the measurement run queue when a battlecard is external-evidence-blocked.
- The bridge joins public controls and local command requirements; it is not evidence that authority, backlinks, market share, AI visibility or traffic have been approved.
- Raw analytics, Search Console exports, private listing URLs, SERP screenshots, AI transcripts and unapproved rollups stay local unless reviewed, redacted and aggregated.
Returns object · 3 ready battlecards and 21 measurement phase rows
Public bridge from ready-for-private-measurement SEO/GEO battlecards to run-now GSC, SERP/AI, authority, market-share, AI-visibility and traffic proof workflows without exposing raw private evidence.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Bridge version date. |
| name | string | Human dataset name. |
| description | string | What the bridge covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the bridge. |
| humanUrl | string | Crawlable report page explaining private-measurement routing. |
| sourceDatasets[] | array<string> | Public controls used to derive and audit the bridge. |
| methodology.joinRules[] | array<string> | How battlecards, phase runs, experiments, baselines and pages are joined. |
| methodology.publicationGates[] | array<string> | GSC, SERP/AI, market-share, AI-visibility and traffic proof gates. |
| methodology.noGoPolicy | string | Why the bridge does not permit public outcome claims. |
| summary.readyForPrivateMeasurementBattlecardCount | number | Battlecards ready for private measurement. |
| summary.runNowPhaseCount | number | Run-now private measurement phases. |
| summary.finalOutcomeGateCount | number | Final AI visibility and traffic proof gates. |
| summary.approvedSnapshotCount | number | Approved market-share snapshots currently published; expected 0 until reviewed rollups exist. |
| summary.publicRankingClaimAllowed | boolean | Always false until reviewed evidence and public claim gates pass. |
| summary.publicMarketShareClaimAllowed | boolean | Always false until approved market-share proof exists. |
| summary.publicAiVisibilityClaimAllowed | boolean | Always false until approved AI visibility proof exists. |
| summary.publicTrafficOutcomeClaimAllowed | boolean | Always false until reviewed traffic proof exists. |
| summary.public500kMonthClaimAllowed | boolean | Always false until reviewed traffic proof approves the target. |
| battlecards[] | array<object> | Ready battlecard rows with phase IDs, experiment IDs, snapshot IDs and no-go conditions. |
| battlecards[].measurementStatus | string | Expected ready-for-private-measurement. |
| battlecards[].runNowPhaseIds[] | array<string> | Public-control, authority, GSC, SERP/AI and quarterly rollup phases. |
| battlecards[].finalOutcomePhaseIds[] | array<string> | AI visibility and traffic outcome proof gates. |
| battlecards[].publicationGate.publicRankingClaimAllowed | boolean | Whether a public ranking claim is allowed for the row. |
| phaseRuns[] | array<object> | One row per run-now or final-outcome phase copied from the measurement queue. |
| phaseRuns[].publicationGate.publicPhaseOutcomeClaimAllowed | boolean | Whether the phase permits a public outcome claim. |
| pageHandoffs[] | array<object> | Target URL to ready battlecard and phase joins. |
Example response
{
"version": "2026-07-07",
"name": "Visa Atlas SEO/GEO private measurement bridge",
"datasetUrl": "/api/public/seo-geo-private-measurement-bridge",
"humanUrl": "/research/seo-geo-private-measurement-bridge-2026",
"summary": {
"readyForPrivateMeasurementBattlecardCount": 3,
"runNowPhaseCount": 15,
"finalOutcomeGateCount": 6,
"approvedSnapshotCount": 0,
"publicRankingClaimAllowed": false,
"publicMarketShareClaimAllowed": false,
"publicAiVisibilityClaimAllowed": false,
"publicTrafficOutcomeClaimAllowed": false,
"public500kMonthClaimAllowed": false
},
"battlecards": [
{
"id": "uk-global-talent-eligibility-private-measurement-bridge",
"status": "ready-for-private-measurement",
"battlecardId": "uk-global-talent-eligibility",
"runNowPhaseIds": ["public-control-check","authority-proof","gsc-experiment","serp-ai-snapshot","quarterly-market-share-rollup"]
}
],
"phaseRuns": [
{
"id": "uk-global-talent-eligibility-public-control-check-private-measurement-bridge",
"phaseId": "public-control-check",
"runClass": "run-now",
"publicationGate": {
"publicPhaseOutcomeClaimAllowed": false,
"publicAggregatePublicationAllowed": false
}
}
]
}- Use this endpoint after the measurement run queue when a battlecard is ready-for-private-measurement.
- The bridge joins public controls and local command requirements; it is not evidence that ranking, AI visibility, market share or traffic outcomes have been approved.
- Raw analytics, Search Console exports, SERP screenshots, AI transcripts, authority account evidence and unapproved rollups stay local unless reviewed, redacted and aggregated.
Returns object · 8 gate checks
Audit-ready release gate for shipping Visa Atlas SEO/GEO changes: compile, source audits, freshness, optional liveness, production build, rendered crawler output, evidence proof checks and outcome-claim boundaries.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Release-gate contract version date. |
| name | string | Human dataset name. |
| description | string | What the release gate covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| datasetUrl | string | Canonical JSON endpoint for the release-gate contract. |
| humanUrl | string | Crawlable report page explaining the gate checks. |
| runnerPath | string | Local release-gate runner script. |
| docsPath | string | Local release-gate documentation. |
| sourceDatasets[] | array<string> | Public controls and evidence datasets that support the gate. |
| methodology.defaultCommand | string | Offline deterministic release-gate command. |
| methodology.releaseSignoffCommand | string | Release sign-off command including network liveness. |
| methodology.privateEvidencePolicy | string | Which raw private evidence stays local. |
| methodology.noGoPolicy | string | Deploy and public outcome-claim no-go conditions. |
| summary.stepCount | number | Number of release-gate checks. |
| summary.requiredStepCount | number | Required offline checks. |
| summary.optionalNetworkStepCount | number | Optional network sign-off checks. |
| summary.blocksPublicOutcomeClaims | boolean | Whether the gate blocks public outcome claims without proof. |
| summary.planningTargetMonthlyVisits | number | 500k/month planning target context, not current traffic proof. |
| steps[] | array<object> | One release-gate check per row. |
| steps[].stepClass | string | compile, source-audit, freshness, network-liveness, build, rendered-audit, claim-boundary or evidence-proof. |
| steps[].status | string | required or optional-network. |
| steps[].command | string | Local command used by or related to the release gate. |
| steps[].sourceSurfaces[] | array<string> | Files, routes, artifacts or datasets checked by the step. |
| steps[].proves[] | array<string> | What the gate proves when it passes. |
| steps[].failureBlocks[] | array<string> | What must not ship or be claimed when the step fails. |
| steps[].privateEvidenceBoundary | string | Which raw evidence stays local for the step. |
Example response
{
"version": "2026-07-07",
"name": "Visa Atlas SEO/GEO release gate contract",
"datasetUrl": "/api/public/seo-geo-release-gate",
"humanUrl": "/research/seo-geo-release-gate-contract-2026",
"summary": {
"stepCount": 8,
"requiredStepCount": 7,
"optionalNetworkStepCount": 1,
"blocksPublicOutcomeClaims": true,
"planningTargetMonthlyVisits": 500000
},
"steps": [
{
"id": "typescript-compile",
"label": "TypeScript app/runtime compile",
"status": "required",
"command": "npm run typecheck"
}
]
}- Use this endpoint before deployment sign-off to inspect exactly what the SEO/GEO release gate proves and blocks.
- Run npm run audit:seo-geo locally for deterministic release checks; add -- --include-liveness for source-refresh or release sign-off requiring live government-source probes.
- This endpoint publishes deploy governance, not proof of rankings, traffic, backlinks, AI citations, market share or the 500k/month planning target.
Returns object · 7 action rules
Audit-ready decision matrix for turning local GSC, SERP and AI answer-surface evidence into content, page and technical SEO/GEO actions without publishing private query data.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Action-map version date. |
| name | string | Human dataset name. |
| description | string | What the action map covers. |
| license | string | Always "CC BY 4.0". |
| attribution | string | The credit to use: "Visa Atlas". |
| sourceDatasets[] | array<string> | Public datasets and contracts used by the action rules. |
| methodology.sourceOfTruth | string | How action rules are derived from GSC opportunity types, battlecards, snapshot protocols and technical controls. |
| methodology.privateDataPolicy | string | Boundary for GSC exports, query strings, clicks, impressions, SERP screenshots and AI transcripts. |
| methodology.completionStandard | string | Why the map proves decision workflow but not ranking, traffic or 500k/month outcomes. |
| methodology.versionInputs | object | Version dates for source contracts used by the map. |
| summary.actionCount | number | Number of action rules. |
| summary.criticalCount | number | Number of critical action gates. |
| summary.commandCount | number | Unique local evidence commands referenced by the map. |
| summary.relatedExperimentCount | number | Battlecard search experiments covered by action rules. |
| summary.noCreateRuleCount | number | Number of explicit anti-thin-page/no-create rules. |
| actions[] | array<object> | One search-demand action rule per row. |
| actions[].actionType | string | title-snippet-answer-refresh, internal-link-authority-push, source-backed-depth-section, canonical-routing-no-create, serp-ai-market-share-escalation, freshness-stale-claim-refresh or experiment-outcome-publication-gate. |
| actions[].trigger | string | Local evidence condition that activates the rule. |
| actions[].localEvidenceInputs[] | array<string> | Private/local evidence inputs required before action. |
| actions[].localCommands[] | array<string> | Local commands used to generate or verify the evidence. |
| actions[].contentChanges[] | array<string> | Allowed content changes. |
| actions[].pageChanges[] | array<string> | Allowed page-level changes. |
| actions[].technicalChanges[] | array<string> | Required technical checks or changes. |
| actions[].noCreateRules[] | array<string> | Rules that prevent thin page creation or unearned outcome claims. |
| actions[].passCriteria[] | array<string> | Conditions required for the action to pass. |
| actions[].privateEvidenceBoundary | string | What evidence stays local unless reviewed and aggregated. |
Example response
{
"version": "2026-07-04",
"name": "Visa Atlas search demand action map",
"summary": {
"actionCount": 7,
"criticalCount": 4,
"commandCount": 20,
"noCreateRuleCount": 15
},
"actions": [
{
"id": "high-impression-low-ctr-snippet-refresh",
"actionType": "title-snippet-answer-refresh",
"priority": "critical",
"localCommands": ["npm run seo:gsc-opportunities -- gsc-queries.csv --json --period-start=YYYY-MM-DD --period-end=YYYY-MM-DD --property-label=gsc-domain-redacted --search-type=web","npm run seo:gsc-battlecard-experiments -- gsc-queries.csv --json --period-start=YYYY-MM-DD --period-end=YYYY-MM-DD --property-label=gsc-domain-redacted --search-type=web"],
"noCreateRules": ["Do not create a new page for a low-CTR query when an existing canonical page can answer it."]
}
]
}- This endpoint publishes action rules, not private Search Console rows or analytics evidence.
- A query opportunity does not justify a new page unless source-backed uniqueness, crawl path and maintenance ownership are proven.
- The action map does not guarantee rankings, traffic, AI citations or market-share gains.
Returns object · 25 crawler policy rows
Public audit of the robots policy, AI/search crawler access rules, crawler-facing discovery surfaces, API Link headers and local server-log proof commands. It proves access intent and discovery wiring without claiming live crawler fetches, citations or rankings.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Audit version date. |
| name | string | Human audit name. |
| datasetUrl | string (URL) | Canonical JSON endpoint for the audit. |
| humanUrl | string (URL) | Crawlable research report explaining the access matrix. |
| robotsTxtUrl | string (URL) | Generated robots.txt URL. |
| sitemapUrl | string (URL) | XML sitemap advertised from robots.txt. |
| summary.explicitAllowCount | number | Crawler rows explicitly allowed in robots.txt. |
| summary.inheritedAllowCount | number | Crawler rows allowed by the wildcard robots rule. |
| summary.deniedCrawlerCount | number | Aggressive scraper rows explicitly disallowed. |
| summary.identityVerificationSourceCount | number | Official identity verification sources documented for WAF and verified-fetch workflows. |
| summary.officialIpRangeSourceCount | number | Official IP range JSON sources referenced by the audit. |
| crawlerPolicies[] | array<object> | One user-agent policy row per crawler or crawler class. |
| crawlerPolicies[].userAgent | string | Crawler user-agent token or robots token. |
| crawlerPolicies[].accessPolicy | string | explicit-allow, inherited-allow or disallow. |
| crawlerPolicies[].evidenceSurfaces[] | array<string> | Public pages or files supporting the row. |
| technicalChecks[] | array<object> | Crawler-facing discovery, header and log-proof controls. |
| identityVerificationSources[] | array<object> | Official crawler identity sources for IP-range, reverse-DNS and robots-token-only verification. |
| identityVerificationSources[].verificationMethod | string | ip-range-json, reverse-dns-and-ip-range or robots-token-only. |
| identityVerificationSources[].ipRangeUrls[] | array<string> | Official crawler publisher IP range JSON URLs, where available. |
| methodology.liveProofPolicy | string | Explanation that live fetch proof requires server logs or Search Console. |
| methodology.identityProofPolicy | string | Explanation that user-agent strings alone are not proof. |
| methodology.commands[] | array<string> | Local audit and server-log commands. |
Example response
{
"version": "2026-07-03",
"name": "Visa Atlas crawler and AI retrieval access audit",
"datasetUrl": "https://visaatlas.org/api/public/crawler-access",
"humanUrl": "https://visaatlas.org/research/crawler-ai-retrieval-access-audit-2026",
"summary": {
"explicitAllowCount": 13,
"inheritedAllowCount": 4,
"deniedCrawlerCount": 8,
"technicalCheckCount": 8,
"identityVerificationSourceCount": 7,
"officialIpRangeSourceCount": 5
},
"crawlerPolicies": [
{
"userAgent": "GPTBot",
"accessPolicy": "explicit-allow",
"robotsDirective": "allow",
"evidenceSurfaces": ["/robots.txt","/api/public/crawler-access","/research/crawler-ai-retrieval-access-audit-2026"]
}
],
"identityVerificationSources": [
{
"userAgents": ["GPTBot"],
"verificationMethod": "ip-range-json",
"ipRangeUrls": ["https://openai.com/gptbot.json"]
}
]
}- Allowed in robots.txt is not a ranking, indexing, citation or traffic guarantee.
- A user-agent string alone is not verified fetch proof; use official IP range JSON or reverse/forward DNS checks where available.
- Raw server logs, Search Console exports and unpublished referral evidence remain local.
- Use npm run seo:botlog -- logs.txt --json to classify live crawler hits from a server log export.
Returns object · 1674 dated records checked
Public source-freshness report for YMYL auditability: every dated record is evaluated against the same SLA tiers used by the internal stale-source tripwire.
Fields
| Field | Type | Description |
|---|---|---|
| asOf | string (ISO date) | Date the freshness report was generated against. |
| thresholds | object | SLA tier definitions for processing-times, money-thresholds and narrative records. |
| totals.checkedItems | number | Total number of dated records evaluated. |
| totals.fresh | number | Records inside their SLA and not yet in the due-soon window. |
| totals.dueSoon | number | Records at or beyond 80% of their SLA threshold. |
| totals.stale | number | Records older than their tier threshold. |
| totals.invalidDates | number | Records with missing or invalid date values. |
| summaries[] | array<object> | Per-tier rollup: total, fresh, dueSoon, stale, invalidDates and oldestAgeDays. |
| stale[] | array<object> | Stale or invalid item records, including URL, field, date, ageDays, thresholdDays and source URL where available. |
| dueSoon[] | array<object> | Records nearing their SLA threshold. |
| items[] | array<object> | Every dated record evaluated by the report. |
Example response
{
"asOf": "2026-07-17",
"totals": {
"checkedItems": 1674,
"fresh": 1621,
"dueSoon": 0,
"stale": 53,
"invalidDates": 0
},
"summaries": [
{
"tier": "processing-times",
"thresholdDays": 45,
"total": 98,
"stale": 53
}
],
"stale": []
}- The same report powers /freshness and npm run audit:stale, so the public dashboard and internal alerting share one SLA model.
- A stale record does not mean the underlying government fact is wrong; it means the Visa Atlas review date has exceeded the public SLA.
Returns object · 98 scored processing clocks
Derived index scoring how usable each official processing-time clock is for planning. The score rewards a published clock, a narrow decision window, percentile disclosure and recent source verification; it does not predict individual case outcomes.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Index version date. |
| name | string | Stable index name. |
| sourceDataset | string | Underlying source dataset: /api/public/processing-times. |
| methodology.scoreMax | number | Maximum possible score, currently 100. |
| methodology.components[] | array<object> | Scoring components and maximum points. |
| methodology.caveats[] | array<string> | Interpretation limits for audit and reuse. |
| summary | object | Counts, average score, grade counts and disclosure counts. |
| strongest[] | array<object> | Top-scoring route clocks. |
| weakest[] | array<object> | Lowest-scoring or most opaque route clocks. |
| rows[] | array<object> | One scored processing-time record per route. |
| rows[].score | number | 0-100 planning-transparency score. |
| rows[].grade | string | strong, usable, watch or opaque. |
| rows[].scoreBreakdown | object | Component points: officialClock, windowWidth, percentileDisclosure and freshness. |
| rows[].delayTrigger | string | When to treat the case as delayed, based on the source record. |
| rows[].sourceUrl | string | Official source URL behind the processing-time record. |
Example response
{
"version": "2026-07-01",
"name": "Visa Atlas processing-time planning reliability index",
"sourceDataset": "/api/public/processing-times",
"summary": {
"count": 98,
"scoreAverage": 66.4,
"notPublishedCount": 8,
"percentileCount": 6
},
"rows": [
{
"id": "au-subclass-482-tss",
"decisionWindow": "2 weeks – 8 weeks",
"score": 90,
"grade": "strong",
"scoreBreakdown": {
"officialClock": 40,
"windowWidth": 20,
"percentileDisclosure": 15,
"freshness": 15
}
}
]
}- A high score means the published clock is more usable for planning; it is not a guarantee that a case will be decided by that date.
- Opaque routes can still be valid routes; the score only reflects published planning transparency.
Returns object · 30 scored migration routes
Derived index scoring tracked skilled and skilled-adjacent routes by planning accessibility. The score combines applicant cost, proof-of-funds exposure, salary floor, processing-clock transparency, sponsor requirement, settlement path and source freshness; it is not a route recommendation or outcome prediction.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Index version date. |
| name | string | Stable index name. |
| sourceDatasets[] | array<string> | Underlying public datasets used by the derived score. |
| methodology.scoreMax | number | Maximum possible score, currently 100. |
| methodology.components[] | array<object> | Scoring components and maximum points. |
| methodology.caveats[] | array<string> | Interpretation limits for audit and reuse. |
| summary | object | Counts, average score, grade counts and mapped-source counts. |
| mostAccessible[] | array<object> | Top-scoring lower-friction planning profiles. |
| highestFriction[] | array<object> | Lowest-scoring higher-friction planning profiles. |
| rows[] | array<object> | One scored route record per cost-to-complete model. |
| rows[].score | number | 0-100 planning-accessibility score. |
| rows[].grade | string | more-accessible, balanced, complex or high-friction. |
| rows[].scoreBreakdown | object | Component points: sunkCost, refundableFunds, salaryFloor, processingReliability, sponsorFlexibility, settlementPath and sourceFreshness. |
| rows[].sunkCost | object | Local and approximate-USD mandatory non-refundable cost range. |
| rows[].refundableFunds | object|null | Local and approximate-USD proof-of-funds exposure, where tracked. |
| rows[].lowestSalaryThreshold | object|null | Lowest mapped route-specific salary or income floor, where tracked. |
| rows[].sourceUrls[] | array<object> | Route, cost, salary, processing and FX source URLs behind the row. |
Example response
{
"version": "2026-07-01",
"name": "Visa Atlas skilled-migration planning accessibility index",
"sourceDatasets": [
"/api/public/cost-to-complete",
"/api/public/processing-reliability",
"/api/public/salary-thresholds",
"/api/public/visas"
],
"summary": {
"count": 30,
"averageScore": 67.1,
"unsponsoredCount": 11,
"settlementPathCount": 24
},
"rows": [
{
"id": "de-chancenkarte",
"score": 89,
"grade": "more-accessible",
"routePath": "/visas/germany/chancenkarte",
"costPath": "/cost-to-complete/germany-chancenkarte",
"sunkCost": {
"approxUsdLabel": "$628-$1,270"
},
"scoreBreakdown": {
"sunkCost": 17,
"refundableFunds": 12,
"salaryFloor": 15,
"processingReliability": 15,
"sponsorFlexibility": 15,
"settlementPath": 10,
"sourceFreshness": 5
}
}
]
}- A high score means lower planning friction in the tracked dimensions; it is not legal advice and not a prediction of eligibility, timing or outcome.
- Use the row sourceUrls and sourceDatasets fields to cite the underlying facts behind each score.
Returns object · 3192 indexed comparison pairs
Derived inventory of indexable country comparison pages. It exposes destination profiles and pair-level metrics for route count, sponsor flexibility, settlement routes, dominant skilled routes, salary floors, processing clocks, tracked sunk cost and recent policy activity.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Dataset version date. |
| name | string | Stable dataset name. |
| sourceDatasets[] | array<string> | Underlying public datasets used to derive the profiles and pair metrics. |
| methodology.indexedPairRule | string | The shared compare-page index gate used to decide which pairs are included. |
| methodology.caveats[] | array<string> | Reuse limits: not legal advice, not a recommendation, not a complete global census. |
| summary | object | Destination count, pair count, editorial overlay count and source dataset count. |
| destinations[] | array<object> | One derived profile per full-coverage comparison destination. |
| destinations[].routeCount | object | Tracked route totals: total, sponsorRequired, sponsorNotRequired and settlementPath. |
| destinations[].dominantSkilledRoute | object|null | Dominant skilled route used by the compare page, where mapped. |
| destinations[].lowestSalaryThreshold | object|null | Lowest mapped salary or income floor in the source-linked salary dataset. |
| destinations[].fastestProcessingClock | object|null | Fastest tracked centrally published processing window for the destination. |
| destinations[].lowestTrackedSunkCost | object|null | Lowest tracked cost-to-complete mandatory non-refundable cost profile. |
| destinations[].sourceUrls[] | array<object> | Government portal and metric source URLs behind the profile. |
| pairs[] | array<object> | One row per indexable /compare/{a}/vs/{b} page. |
| pairs[].path | string | Canonical compare page path. |
| pairs[].hasEditorialNote | boolean | Whether the pair includes an authored comparison overlay. |
| pairs[].metrics[] | array<object> | Pair-level metric rows with metric, a, b and basis fields. |
| pairs[].sourceUrls[] | array<object> | Deduplicated source URLs backing the comparison. |
Example response
{
"version": "2026-07-01",
"name": "Visa Atlas country comparison data",
"sourceDatasets": [
"/api/public/visas",
"/api/public/destinations",
"/api/public/salary-thresholds",
"/api/public/processing-times",
"/api/public/cost-to-complete",
"/api/public/skilled-migration-accessibility",
"/api/public/policy-updates"
],
"summary": {
"destinationCount": 178,
"pairCount": 3192,
"editorialPairCount": 20
},
"pairs": [
{
"id": "al-vs-au",
"path": "/compare/albania/vs/australia",
"hasEditorialNote": false,
"metrics": [
{
"metric": "trackedRoutes",
"a": 6,
"b": 9
}
]
}
]
}- Use pairs[].path when citing the human comparison page and sourceUrls/sourceDatasets when citing the underlying facts.
- This endpoint mirrors the rendered /compare index gate; it is not a personalised immigration recommendation.
Returns array<object> · 37 fee breakdowns
Government-published fee breakdowns by destination and visa route — every line item with its amount and currency, a worked example for the headline case, and guidance on dependants and volatility.
Fields
| Field | Type | Description |
|---|---|---|
| destinationIso | string | Destination key. |
| visaSlug | string | Route slug the fees apply to. |
| lines[] | array<object> | Individual fee lines (see sub-fields). |
| lines[].label | string | What the charge is. |
| lines[].amountLocal | number | Amount in the local currency. |
| lines[].currency | string (ISO 4217) | Currency code, e.g. "GBP". |
| lines[].mandatory | boolean | Whether the line is unavoidable (false = optional/conditional, e.g. priority service). |
| lines[].per | string? | Unit, when the charge recurs, e.g. "per year of leave, per person". |
| lines[].note | string? | Caveats or conditions. |
| lines[].sourceUrl | string? | Line-specific official source, where it differs from the record source. |
| workedExample | object | A representative all-in total: { label, totalLocal, currency, breakdown[] }. |
| dependantFees | object? | Dependant guidance: { perDependant, caveats? }. |
| summary | string | Plain-language headline cost. |
| volatility | string | What recently changed and what to watch — the figure most likely to move. |
| sourceName | string | Name of the primary source. |
| sourceUrl | string | Official primary source URL. |
| lastChecked | string (ISO date) | When we last verified the figures. |
Example response
[
{
"destinationIso": "uk",
"visaSlug": "skilled-worker",
"lines": [
{ "label": "Application fee (up to 3 years, outside UK, general)", "amountLocal": 819, "currency": "GBP", "mandatory": true, "sourceUrl": "https://www.gov.uk/skilled-worker-visa/how-much-it-costs" },
{ "label": "Immigration Health Surcharge (IHS)", "amountLocal": 1035, "currency": "GBP", "per": "per year of leave, per person", "mandatory": true, "note": "Reduced to £776/year for students and under-18s." }
],
"workedExample": {
"label": "Single applicant, 3-year CoS, general rate, no priority",
"totalLocal": 3943.2,
"currency": "GBP",
"breakdown": ["£819 application fee", "£3,105 IHS (£1,035 × 3 years)", "£19.20 biometrics", "Plus £525 CoS fee (typically borne by the sponsor)"]
},
"dependantFees": { "perDependant": "Each dependant pays the same application fee plus their own IHS…" },
"summary": "The UK Skilled Worker visa costs around £3,950 in government fees…",
"volatility": "IHS rose 66% on 6 February 2024 and remains £1,035/year…",
"sourceName": "GOV.UK — Skilled Worker visa: how much it costs",
"sourceUrl": "https://www.gov.uk/skilled-worker-visa/how-much-it-costs",
"lastChecked": "2026-05-31"
}
]- Amounts are exact local-currency figures; we do not convert between currencies in this dataset.
- A line with mandatory:false is optional or conditional — read its note before adding it to a total.
Returns array<object> · 30 route cost models
All-in route cost models that separate non-refundable sunk costs from refundable proof-of-funds requirements. Use this when the question is "what do I actually need to budget?", not just "what is the government visa fee?".
Fields
| Field | Type | Description |
|---|---|---|
| routeKey | string | Stable internal key for the cost model. |
| pageSlug | string | URL slug for /cost-to-complete/{pageSlug}. |
| destinationIso | string | Destination key. |
| visaSlug | string | Route slug the model applies to. |
| title | string | Human-readable model title. |
| summary | string | Plain-language explanation of what the model includes. |
| lines[] | array<object> | Line-item cost records. |
| lines[].label | string | Cost line label. |
| lines[].amountLocal | number? | Exact amount in local currency when a single figure applies. |
| lines[].minLocal | number? | Lower bound when the cost is a range. |
| lines[].maxLocal | number? | Upper bound when the cost is a range. |
| lines[].currency | string (ISO 4217) | Currency code. |
| lines[].kind | string | government-fee, proof-of-funds, service or insurance. |
| lines[].refundable | boolean | True when the money is shown or blocked rather than normally lost. |
| lines[].mandatory | boolean | Whether the line is part of the baseline cost model. |
| lines[].indicative | boolean? | True where the figure is an editorial estimate or provider range rather than one official tariff. |
| lines[].sourceName | string? | Source label for this line. |
| lines[].sourceUrl | string? | Source URL for this line, where available. |
| methodologyNote | string | How the sunk/refundable split is calculated. |
| lastChecked | string (ISO date) | When the model was last verified. |
Example response
[
{
"routeKey": "de-chancenkarte",
"pageSlug": "germany-chancenkarte",
"destinationIso": "de",
"visaSlug": "chancenkarte",
"title": "Germany Chancenkarte - total cost to complete",
"lines": [
{ "label": "Consular visa application fee", "amountLocal": 75, "currency": "EUR", "kind": "government-fee", "refundable": false, "mandatory": true },
{ "label": "Blocked account funding", "amountLocal": 13092, "currency": "EUR", "kind": "proof-of-funds", "refundable": true, "mandatory": true }
],
"methodologyNote": "Sunk-cost range sums every mandatory, non-refundable line...",
"lastChecked": "2026-06-22"
}
]- Do not add refundable proof-of-funds lines to non-refundable sunk-cost totals.
- Indicative lines should be quoted as ranges or caveats, not exact government tariffs.
Returns array<object> · 21 destination blocks · 61 thresholds
Minimum-salary floors by destination, grouped into one block per destination. Each block holds the individual route thresholds with their local-currency amount, basis and effective date.
Fields
| Field | Type | Description |
|---|---|---|
| destinationIso | string | Destination key. |
| overview | string | How the destination structures its salary floors. |
| thresholds[] | array<object> | The individual route thresholds (see sub-fields). |
| thresholds[].routeLabel | string | Which floor this is. |
| thresholds[].visaSlug | string | Route the threshold applies to. |
| thresholds[].amountLocal | number | Threshold amount in local currency. A value of 0 means the authority does not publish one fixed numeric floor; read description/overview for the pay test. |
| thresholds[].currency | string (ISO 4217) | Currency code. |
| thresholds[].basis | string | Period the amount is expressed over: "annual", "monthly" or "hourly". |
| thresholds[].approxUsd | number | Approximate USD equivalent — for cross-country comparison and ranking only, not a live FX quote. |
| thresholds[].description | string | Context and the rule (e.g. higher-of going rate). |
| thresholds[].effectiveFrom | string (ISO date) | When this amount took effect. |
| thresholds[].sourceUrl | string | Official source URL. |
| thresholds[].sourceName | string | Name of the source. |
| volatility | string | Recent movements and what to watch. |
| lastChecked | string (ISO date) | When the block was last verified. |
Example response
[
{
"destinationIso": "uk",
"overview": "The UK Home Office sets separate salary floors for variants of the Skilled Worker route…",
"thresholds": [
{
"routeLabel": "Skilled Worker — general threshold",
"visaSlug": "skilled-worker",
"amountLocal": 41700,
"currency": "GBP",
"basis": "annual",
"approxUsd": 49000,
"description": "The default minimum salary, raised to £41,700 on 22 July 2025…",
"effectiveFrom": "2025-07-22",
"sourceUrl": "https://www.gov.uk/guidance/immigration-rules/immigration-rules-appendix-skilled-worker",
"sourceName": "GOV.UK — Appendix Skilled Worker"
}
],
"volatility": "The general rate rose from £26,200 to £38,700 in April 2024, then to £41,700 on 22 July 2025…",
"lastChecked": "2026-05-30"
}
]- approxUsd is a rounded comparison figure only — for the real requirement always use amountLocal + currency. If amountLocal is 0, do not read it as a zero salary requirement; the route uses a no-fixed-floor pay test described in the row.
Returns array<object> · 98 bands
Typical decision-time bands by destination and visa route, taken from each authority where it publishes one. Where no central decision time exists, the band is flagged rather than guessed.
Fields
| Field | Type | Description |
|---|---|---|
| destinationIso | string | Destination key. |
| visaSlug | string | Route slug. |
| typicalMinDays | number? | Lower bound of the typical decision window, in days. Absent when notPublished is true. |
| typicalMaxDays | number? | Upper bound, in days. Absent when notPublished is true. |
| p80Days | number? | 80th-percentile day count, where the authority publishes one. |
| summary | string | Plain-language window and what it measures. |
| note | string? | Caveats (priority services, backlogs, etc.). |
| notPublished | boolean? | true when no central decision time exists (granted on arrival, route closed, or not committed to). |
| guidance | string? | What to check instead, present when notPublished is true. |
| sourceName | string | Name of the source. |
| sourceUrl | string | Official source URL. |
| lastChecked | string (ISO date) | When last verified. |
Example response
[
{
"destinationIso": "uk",
"visaSlug": "skilled-worker",
"typicalMinDays": 15,
"typicalMaxDays": 21,
"summary": "GOV.UK publishes 3 weeks as the typical decision window for applications made outside the UK.",
"note": "Priority service aims for 5 working days; super-priority next working day…",
"sourceName": "GOV.UK — Visa decision waiting times",
"sourceUrl": "https://www.gov.uk/guidance/visa-decision-waiting-times-applications-outside-the-uk",
"lastChecked": "2026-04-20"
},
{
"destinationIso": "ie",
"visaSlug": "stamp-4",
"notPublished": true,
"summary": "Stamp 4 is granted on arrival or at registration; there is no separate consular decision period.",
"guidance": "Check the specific pathway for the permission rules that apply.",
"sourceName": "Irish Immigration Service — Registration Office",
"sourceUrl": "https://www.irishimmigration.ie/registering-your-immigration-permission/",
"lastChecked": "2026-04-20"
}
]- These are decision windows, not end-to-end timelines — appointment, skills-assessment and card-issuance steps often dwarf the decision itself.
Returns object · 10 current categories
A derived 2026 category-based selection tracker over the official Express Entry draw history and IRCC current category guidance. Use it when you need category status, category CRS ranges, categories that have not drawn yet, and program rounds kept separate from category rounds.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Report version date; matches the draw feed reconciliation date. |
| sourceDatasets[] | array<string> | Underlying public datasets, currently /api/public/express-entry-draws. |
| officialSources[] | array<object> | IRCC source records for draw rounds and category-based selection guidance. |
| methodology | object | Source-of-truth statement, included-row rule and caveats. |
| summary | object | Counts for current categories, drawn/not-drawn categories, category rounds and invitations. |
| summary.latestCategoryDraw | object|null | Most recent category-based round in the tracked 2026 draw history. |
| summary.lowestCategoryCrs | object|null | Lowest category-based CRS cut-off in the tracked 2026 draw history. |
| rows[] | array<object> | One row per current IRCC category, including rows with no 2026 draw. |
| rows[].officialLabel | string | IRCC category label. |
| rows[].drawnThisYear | boolean | Whether that category has held at least one 2026 category-based round. |
| rows[].roundsThisYear | number | Number of 2026 category rounds for that category. |
| rows[].invitationsThisYear | number | ITAs issued in that category in 2026. |
| rows[].minCrsThisYear | number|null | Lowest 2026 CRS cut-off for the category; null if no draw yet. |
| rows[].maxCrsThisYear | number|null | Highest 2026 CRS cut-off for the category; null if no draw yet. |
| rows[].latestDraw | object|null | Latest draw for that category, with round/date/ITAs/CRS; null if none. |
| programDrawsThisYear[] | array<object> | Canadian Experience Class, Provincial Nominee Program and general rounds, separated from category rows. |
Example response
{
"version": "2026-07-15",
"name": "Visa Atlas Canada Express Entry category tracker",
"sourceDatasets": ["/api/public/express-entry-draws"],
"summary": {
"categoryCount": 10,
"categoriesDrawn": 5,
"categoriesNotDrawn": 5,
"latestCategoryDraw": {"round":426,"date":"2026-07-10","category":"Senior managers","invitations":500,"crsCutoff":392}
},
"rows": [
{
"category": "Healthcare and social services",
"officialLabel": "Healthcare and social services occupations",
"drawnThisYear": true,
"roundsThisYear": 2,
"invitationsThisYear": 8000,
"minCrsThisYear": 467,
"maxCrsThisYear": 475,
"latestDraw": {"round":422,"date":"2026-06-25","category":"Healthcare and social services","invitations":4000,"crsCutoff":475,"daysSinceDraw":20,"crsChangeFromPreviousCategoryDraw":8}
}
]
}- Rows with drawnThisYear=false are intentionally present: no-draw categories are useful evidence for category-specific queries.
- A category CRS cut-off is a historical result for one round, not a target score or invitation guarantee.
Returns object · 41 rounds
The round-by-round history of Canada Express Entry invitations, confirmed against IRCC’s official feed and refreshed weekly. Unlike the other endpoints this returns an object with provenance at the top and the draws array underneath.
Fields
| Field | Type | Description |
|---|---|---|
| officialSource | object | IRCC source: { label, url, authority }. |
| lastVerified | string (ISO date) | When the feed was last reconciled against IRCC. |
| draws[] | array<object> | The rounds, newest first (see sub-fields). |
| draws[].round | number | IRCC sequential round number. |
| draws[].date | string (ISO date) | Draw date. |
| draws[].category | string | Program or category-based selection type, e.g. "French-language proficiency", "Canadian Experience Class", "Provincial Nominee Program", "Healthcare and social services", "Trade occupations", "Physicians". |
| draws[].invitations | number | Invitations to apply (ITAs) issued. |
| draws[].crsCutoff | number | Comprehensive Ranking System cut-off score for the round. |
Example response
{
"officialSource": {
"label": "IRCC — Express Entry rounds of invitations",
"url": "https://www.canada.ca/en/immigration-refugees-citizenship/services/immigrate-canada/express-entry/submit-profile/rounds-invitations.html",
"authority": "Immigration, Refugees and Citizenship Canada"
},
"lastVerified": "2026-07-15",
"draws": [
{ "round": 426, "date": "2026-07-10", "category": "Senior managers", "invitations": 500, "crsCutoff": 392 }
]
}- A CRS cut-off is a per-round result, not a target — category draws can post far lower cut-offs than program draws because the eligible pool is smaller.
Returns object · 7 recorded movements
Machine-readable diff feed for tracked fees, salary thresholds and processing-time facts. Each change carries a stable fact ID, old value, new value, effective date, current owning route and primary source.
Fields
| Field | Type | Description |
|---|---|---|
| lastModified | string (ISO date) | Most recent changedOn date in the feed. |
| count | number | Number of recorded movements. |
| changes[] | array<object> | Fact-change records, newest first. |
| changes[].changeId | string | Stable ID combining factId and changedOn. |
| changes[].factId | string | Stable fact identifier from the verification registry. |
| changes[].kind | string? | salary-threshold, fee or processing-time. |
| changes[].label | string | Human label for the changed fact. |
| changes[].jurisdiction | string? | Destination or jurisdiction affected. |
| changes[].owningRoute | string? | Current human page that publishes the fact. |
| changes[].from | string | Previous observed value. |
| changes[].to | string | New observed value. |
| changes[].changedOn | string (ISO date) | Effective date of the movement. |
| changes[].sourceName | string? | Name of the primary source. |
| changes[].sourceUrl | string | Official primary source URL for the new value. |
| changes[].currentValue | string? | Current value published in the registry. |
| changes[].currentAsOf | string (ISO date)? | Effective/review date of the current value. |
| changes[].note | string? | Context on the superseded value when available. |
Example response
{
"lastModified": "2026-03-01",
"count": 7,
"changes": [
{
"changeId": "salary:ie:critical-skills-employment-permit-general-floor@2026-03-01",
"factId": "salary:ie:critical-skills-employment-permit-general-floor",
"kind": "salary-threshold",
"label": "Critical Skills Employment Permit - general floor salary floor",
"jurisdiction": "Republic of Ireland",
"owningRoute": "/salary-thresholds/ireland",
"from": "38000 EUR (annual)",
"to": "40904 EUR (annual)",
"changedOn": "2026-03-01",
"sourceName": "DETE - Critical Skills Employment Permit",
"sourceUrl": "https://enterprise.gov.ie/en/what-we-do/workplace-and-skills/employment-permits/permit-types/critical-skills-employment-permit/",
"currentValue": "40904 EUR (annual)",
"currentAsOf": "2026-03-01"
}
]
}- Use changeId for de-duplication. Use owningRoute for the human-readable current figure and sourceUrl for the issuing authority.
Returns object · 5 months with recorded movements
Derived month-by-month archive of recorded fee, salary-threshold and processing-time movements. It groups /api/public/fact-changes by changedOn month and adds same-month policy-update context; policy rows are not counted as figure movements.
Fields
| Field | Type | Description |
|---|---|---|
| version | string (ISO date) | Report version date. |
| name | string | Stable report name. |
| sourceDatasets[] | array<string> | Underlying public datasets: fact changes and policy updates. |
| methodology.period | string | Grouping period, currently calendar-month. |
| methodology.caveats[] | array<string> | Limits for reuse and interpretation. |
| summary | object | Counts by month, kind and year. |
| latestMonth | object|null | Most recent month that has a recorded old-to-new figure movement. |
| months[] | array<object> | Monthly archive rows, newest first. |
| months[].changes[] | array<object> | Fact-change rows for the month, each with old value, new value, source and changelog anchor. |
| months[].policyContext[] | array<object> | Policy updates whose display date falls in the same month. |
| changes[] | array<object> | Flattened fact-change rows with detailPath added. |
Example response
{
"version": "2026-07-01",
"name": "Visa Atlas monthly immigration figure changes",
"sourceDatasets": ["/api/public/fact-changes", "/api/public/policy-updates"],
"summary": {
"changeCount": 7,
"monthCount": 5,
"latestChangeMonthLabel": "March 2026"
},
"months": [
{
"month": "2026-03",
"label": "March 2026",
"changeCount": 1,
"changes": [
{
"changeId": "salary:ie:critical-skills-employment-permit-general-floor@2026-03-01",
"from": "38000 EUR (annual)",
"to": "40904 EUR (annual)",
"detailPath": "/changelog#change-salary-ie-critical-skills-employment-permit-general-floor-2026-03-01"
}
]
}
]
}- Months with no recorded old-to-new figure movement are omitted from months[].
- Use /api/public/fact-changes for the canonical movement records and this endpoint when you need calendar-month grouping.
Using the data
Attribution
Reuse is welcome under CC BY 4.0 — credit “Visa Atlas” and, where you can, link the page or endpoint you took a figure from. For the underlying fact, please also cite the original government authority (each record links it). See Use our data for citation examples.
Staying current
Figures move. Two RSS feeds let you track changes without polling: policy-updates.xml (dated rule changes) and changelog.xml (every fee/threshold/processing figure that moved, from → to). The Express Entry draws are reconciled against IRCC weekly. Figure-change history is also available as JSON at /api/public/fact-changes.
Errors
There is no error envelope: a valid endpoint returns its JSON with HTTP 200; an unknown path returns the standard 404 page. If a field you expect is missing, it is simply not applicable to that record (optional fields are omitted, not nulled).
Other machine-readable surfaces
- /api/public — the self-describing catalog with schema.org Dataset metadata.
- llms.txt and llms-full.txt — a plain-text index of the whole site.
- AI agents and immigration data — the retrieval contract, citation rules, public entry points, and MCP tool contract in one page.
- Research reports — original analysis computed from these same figures, with method and limitations stated.
- The read-only MCP (Model Context Protocol) tool wrapper exposes the same verified data with its source and last-verified date on every result; use the static JSON endpoints as the public web source of truth.