June 18, 2026 · 8 min read · Use cases
The Schengen visa flow your travel app probably gets wrong.
Twenty-six countries, one visa — except eligibility depends on the passport, not the residence, and four common interpretations of the 90-in-180 rule are all wrong. We see travel apps ship the wrong logic constantly. Here is the right shape.
The mistake that shows up in 80% of travel apps
A user opens your app, sets their location to Berlin, and types a destination of Rome. The app says "no visa required, Schengen area." This is correct only if the user holds a Schengen-eligible passport. A Brazilian living in Berlin still needs no visa for Italy. A Pakistani living in Berlin still does. A Singaporean visiting from Singapore doesn't. An Indian visiting from Mumbai does.
Residence is irrelevant. Passport is everything. Travel apps that key visa status off the user's IP geolocation or saved profile location ship a UI that gets the answer wrong for every immigrant, every expatriate, every traveller passing through.
The 90-in-180 rule, properly stated
The Schengen short-stay rule allows up to 90 days within any rolling 180-day window. Four common misreadings:
- Wrong: "90 days per calendar year." It's a rolling window, not a calendar reset.
- Wrong: "90 days per visit, with a one-day reset between visits." The clock counts every day in the area, summed across visits inside the 180-day window.
- Wrong: "The 180 days starts from your first entry." The 180-day window is computed backwards from any reference date.
- Wrong: "The clock pauses while you're outside the area." Days outside don't add to the count, but they don't reset it either — they just age out of the rolling window.
The correct test, computed at any reference date: count how many days in the previous 180 days were spent inside the Schengen area. If that number plus the planned stay exceeds 90, the trip is not allowed on short-stay rules. The European Commission ships a calculator. Your app should embed equivalent logic, not paraphrase the rule in a paragraph.
Per-country rules layered on top
The common visa is the floor. Member states layer national rules on top:
- Italy requires hotel registration within 48 hours, with the accommodation responsible for filing.
- Germany requires Anmeldung within 14 days for stays beyond a certain length, even on tourist status if you take an apartment.
- Greece distinguishes Schengen short-stay from "national long-stay" visas with different documentary thresholds.
- Poland's border control has historically asked for proof of accommodation more aggressively than its neighbours, especially at eastern crossings.
A travel app that lumps "Schengen = no visa" without surfacing the per-country obligations sends users into avoidable trouble at the border or at the local police station.
The right data shape
The /v1/visa endpoint returns a matrix keyed by passport country and destination country. The Schengen relationship is derivable from the matrix — any one of the 26 member countries' rows tells you the visa-free / visa-on-arrival / e-visa / visa-required status for that passport.
GET /v1/visa?passport=IN&destination=IT
{
"passport": "IN",
"destination": "IT",
"status": "visa_required",
"max_stay_days": 90,
"rule": "schengen_90_180",
"schengen_member": true,
"notes": [
"Italy hotel registration required within 48h",
"Travel medical insurance min EUR 30,000 required"
]
}
To answer "can this user enter any Schengen country," you read the
schengen_member flag on the destination row plus the
status on any one of the 26 member rows for the same
passport. The matrix is consistent — if a passport is visa-free for
France, it is visa-free for Italy on the common visa, modulo the
per-country layered notes.
Worked example: a Brazilian planning Rome → Athens → Reykjavik
Brazilian passport. Italy, Greece, Iceland — Iceland is in Schengen despite not being in the EU. The matrix returns visa-free 90-in-180 for all three. The 90-day clock counts continuously across the three legs because all three are in the area. Total stay is 18 days; well under the limit; no application needed. Without the matrix, your app has to know that Iceland is in Schengen but not the EU, that Norway and Switzerland are too, that Croatia joined in 2023, and that Cyprus, Romania, and Bulgaria have a partial relationship. The matrix already knows.
What the API doesn't promise
Visa rules change. We track the public sources and re-pull weekly, but the legally authoritative answer is always the destination country's consulate. Show the matrix as guidance, link to the official source, and don't promise outcomes you don't control.