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:

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:

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.

Sign up — free See India coverage →