Visa & study-permit data, cited, versioned, honest about unknowns.
One REST API for program rules: requirements, fees, processing and rights. Every fact carries its official source, a quote and a freshness date. Every answer names the release it came from. Where a source is silent, the API says unknown instead of guessing.
- Official sources only, every fact quoted
- Versioned releases, reproducible answers
- Unknowns stated · no approval probabilities
- English-only data
Two ways in, one dataset behind both.
REST API
Call it from your backend. Quickstart in curl, JavaScript and Python, then a walk through the data model with France as the example.
MCP for agents
Give Claude, Cursor, Copilot, Codex or Gemini the same answers as tools. Setup for each client, plus the rules an agent must follow.
Coverage
Which countries pass the quality gate, and what is still missing for each of them, fact by fact.
API reference
Every endpoint, parameter, schema and error code, rendered from the OpenAPI document the API serves.
Your own key, in a minute.
- 01
Create a free account
One VisaPassage login. The free plan starts right away with 500 units a month.
- 02
Create an API key
Name it per app or environment. The full key is shown once. We store only its hash.
- 03
Call /api/v1
Send it as Authorization: Bearer. Every response reports your remaining units and rate limit in its headers.
Plans
Usage is counted in units: a match is 5 units, every other call is 1. Free covers evaluation. Starter covers production traffic, with overage at Apify's unit price so it never costs more than pay-per-use once you pass 14,500 units a month. Enterprise is for larger volumes and custom terms.
Free
No cardEvaluate the data and build a prototype.
$0/ month
- Units / month
- 500
- Per 1k units
- —
- Overage
- Hard cap
- Requests / min
- 60
- API keys
- 2
Starter
A side project or an early product in production.
$29/ month
- Units / month
- 15,000
- Per 1k units
- $1.93
- Overage
- $2 / 1k
- Requests / min
- 300
- API keys
- 5
Enterprise
Over 100,000 units a month, custom terms or invoicing.
Custom
Volume pricing, an agreed rate limit, invoicing and a data agreement for your legal team.
Talk to us
Which plan fits?
Enter a month of traffic. We price it on every plan, overage included, and mark the cheapest.
7,000 units / month
- FreeOver the cap
- StarterCheapest$29/ month
The same volume on Apify: $14
- A match (POST /api/v1/match) is 5 units. Every other endpoint is 1 unit. openapi.json is free.
- Only successful responses count. A failed call is refunded automatically.
- The quota and rate limit belong to the account and are shared by all of its keys.
- Starter opens in November 2026. Until then every account runs on Free. Prices are in USD, excluding tax.
- Also on Apify at $0.002 a unit ($0.01 a match), billed by Apify.
One request, a cited answer.
- 01Create a free account and an API key.
- 02POST a traveller profile to /api/v1/match.
- 03Read fit, costs and unknown_checks. Every value cites its source.
curl -s https://visapassage.com/api/v1/match \ -H "Authorization: Bearer $VISAPASSAGE_KEY" \ -H "Content-Type: application/json" \ -d '{"purpose":"study.degree","scope":{"destinations":["FR"]},"citizenships":["UA"],"citizenships_complete":true,"languages":[{"language":"uk","native":true},{"language":"fr","cefr":"B2"}],"funds":{"min":"8400.00","currency":"EUR","forms":["bank_statement"]},"education_isced":6,"stay_months":12,"dependents":{"spouse":false,"children":0}}'const res = await fetch("https://visapassage.com/api/v1/match", { method: "POST", headers: { Authorization: `Bearer ${process.env.VISAPASSAGE_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "purpose": "study.degree", "scope": { "destinations": [ "FR" ] }, "citizenships": [ "UA" ], "citizenships_complete": true, "languages": [ { "language": "uk", "native": true }, { "language": "fr", "cefr": "B2" } ], "funds": { "min": "8400.00", "currency": "EUR", "forms": [ "bank_statement" ] }, "education_isced": 6, "stay_months": 12, "dependents": { "spouse": false, "children": 0 } }),});const result = await res.json();console.log(result.release_id, result.results);import os, requests res = requests.post( "https://visapassage.com/api/v1/match", headers={"Authorization": f"Bearer {os.environ['VISAPASSAGE_KEY']}"}, json={ "purpose": "study.degree", "scope": { "destinations": [ "FR" ] }, "citizenships": [ "UA" ], "citizenships_complete": True, "languages": [ { "language": "uk", "native": True }, { "language": "fr", "cefr": "B2" } ], "funds": { "min": "8400.00", "currency": "EUR", "forms": [ "bank_statement" ] }, "education_isced": 6, "stay_months": 12, "dependents": { "spouse": False, "children": 0 } },)result = res.json()print(result["release_id"], result["results"]){ "release_id": 17, "as_of": "2026-10-13", "engine_version": "1.3.0", "results": [ { "slug": "fr-visa-de-court-sejour-etudiant-concours", "fit": "all_met", "government_total": { "value_state": "unknown" }, "unknown_checks": [ "admission_letter", "financial_means", "health_insurance", "language_proficiency" ] }, { "slug": "fr-vls-ts-etudiant", "fit": "has_unmet", "government_total": { "value_state": "unknown" }, "unknown_checks": [ "health_insurance", "language_proficiency" ] } ]}Coverage, country by country.
1 covered · 31 in progress · 32 in the first slice
| Country | Status | Programs | Material facts | Scenarios | Detail |
|---|---|---|---|---|---|
| Covered | 3 | 33/33 | 5/5 | What we have | |
| In progress | 1 | 6/9 | 0/5 | What we have | |
| In progress | 0 | — | — | Not started | |
| In progress | 0 | — | — | Not started | |
| In progress | 0 | — | — | Not started | |
| In progress | 0 | — | — | Not started | |
| In progress | 0 | — | — | Not started | |
| In progress | 0 | — | — | Not started |


