Developer reference · 1 June 2026
API & data reference
Every figure on Visa Atlas — fees, salary floors, processing times, policy changes and the Canada Express Entry draw history — 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.
At a glance
- Base URL
- https://visaatlas.org/api/public
- Format
- JSON (UTF-8)
- Auth
- None — fully open
- Method
- GET only
- License
- CC BY 4.0
- Rate limits
- None stated — static, be reasonable
Endpoints
- Catalog
/api/public - Visa routes
/api/public/visas - Destinations
/api/public/destinations - Fees
/api/public/fees - Salary thresholds
/api/public/salary-thresholds - Processing times
/api/public/processing-times - Canada Express Entry draws
/api/public/express-entry-draws
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 · 4 datasets described
A self-describing index of the figure datasets, plus a schema.org 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[].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. |
| jsonld[] | array<object> | A schema.org Dataset object per dataset (name, description, license, creator, distribution; the Express Entry entry also carries 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": 14,
"license": "CC BY 4.0",
"attribution": "Visa Atlas",
"primarySourceNote": "Every figure links to its official government primary source…"
}
// …salary-thresholds, processing-times, express-entry-draws
],
"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 array<object> · 269 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> · 47 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> · 14 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> · 10 destination blocks · 42 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. |
| 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.
Returns array<object> · 84 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 · 33 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-06-01",
"draws": [
{ "round": 418, "date": "2026-05-28", "category": "French-language proficiency", "invitations": 4500, "crsCutoff": 409 }
]
}- 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.
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.
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.
- Research reports — original analysis computed from these same figures, with method and limitations stated.
- A read-only MCP (Model Context Protocol) server is also available for AI agents, exposing the same verified data with its source and last-verified date on every result.