Orizn
Retour au blog
📝
Guides4 min de lecture

Transit Visa Rules by API: What the Orizn Visa API Actually Returns

Transit visa rules are one of the messiest corners of travel data: they depend on the traveler's nationality, the departure and arrival countries, the…

Transit visa rules are one of the messiest corners of travel data: they depend on the traveler's nationality, the departure and arrival countries, the airport, and sometimes the airline. Most datasets flatten this into a single yes/no per country, which is quietly wrong for a lot of passports. Here is what the Orizn Visa API actually returns for transit, and — just as important — what it does not cover.

The endpoint

Transit information is one field inside the main visa lookup, not a separate product:

GET /api/v1/visa?passport=FRA&destination=JPN&lang=en
Host: https://visa.orizn.app
x-api-key: YOUR_API_KEY

A minimal call with curl:

curl "https://visa.orizn.app/api/v1/visa?passport=FRA&destination=JPN" \
  -H "x-api-key: YOUR_API_KEY"

Relevant slice of the response:

{
  "data": {
    "passport": "FRA",
    "destination": "JPN",
    "requirement": "visa_free",
    "visa_free_days": 90,
    "transit_visa": {
      "hubs": [
        {
          "airport": "NRT",
          "city": "Tokyo",
          "transit_visa_required": false,
          "transit_free_hours": 24
        }
      ]
    }
  },
  "meta": {
    "lang": "en",
    "api_version": "1.1",
    "coverage": "199 passports x 250 destinations",
    "languages": 15
  }
}

For a trip with connections rather than a single pair, the itinerary endpoint takes a list of stops plus a transit array of countries being passed through:

curl -X POST "https://visa.orizn.app/api/v1/visa/decision" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "passport": "FRA",
        "passport_expiry": "2027-03-01",
        "itinerary": [
          { "country": "THA", "from": "2026-09-01", "to": "2026-09-20" }
        ],
        "transit": ["SGP"],
        "purpose": "tourism"
      }'

For that Singapore transit leg, the documented example response returns:

{
  "transit": [
    {
      "country": "SGP",
      "status": "destination_rule",
      "granularity": "destination",
      "note": "Applies to the airport, not to this nationality. Confirm with the carrier before booking."
    }
  ]
}

That status and note are not filler — they are the documented behavior for how the API handles transit, and they matter more than the happy-path example above.

What "transit_visa" actually covers, and what it doesn't

The documentation is specific about the limits here, so the honest version is worth stating plainly:

  • A transit rule exists for 44 of the 250 destinations in the dataset. For the other 206, a transit query returns status: "unknown".
  • Where a rule does exist, it is recorded per transited country, not per nationality. In practice that means the API can tell you a given airport's general transit policy, but — per the documentation — it "never says whether this passport may transit." The /decision endpoint's own example makes the same point: the note explicitly tells the caller to confirm with the carrier.
  • These gaps are not silent. Every /decision response includes an unknowns array that states, per field and per country, what could not be determined and why — so a client that checks for status: "unknown" never has to guess whether transit was actually evaluated.

If your product needs a confident "yes, this passport can transit through this airport without a visa," the current dataset cannot give you that for most of the map. It can tell you when a hub-level transit-free window exists (as in the NRT/Tokyo example above, 24 hours), and it can tell you, explicitly, when it doesn't know.

Authentication and access

  • Header: x-api-key: YOUR_API_KEY (or the query parameter ?api_key=YOUR_API_KEY when a header isn't available).
  • Base URL: https://visa.orizn.app.
  • /api/v1/visa/check — a lighter yes/no lookup — is also reachable without a key when called from visa.orizn.app, localhost, or a Chrome extension origin, per the documentation; it does not include the transit_visa field.

Plans and quota

  • Free: 100 requests/month, no card required, English only, core fields plus upgrade stubs.
  • Commercial: $49/month, 30,000 requests/month, the right to serve our answers to your paying users, unlocks all 15 languages and extended fields except remote-work-visa and reciprocity history.
  • Production: $199/month, 250,000 requests/month, a 99.9% uptime SLA and a webhook when a record changes, returns all 32 documented fields including bidirectional embassy info.

Over quota, every counted call (/visa, /visa/check, /visa/bulk, /visa/group, /visa/decision) returns:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Reset: 2026-10-01T00:00:00Z
{
  "error": "Monthly limit exceeded (100 req/month on free plan). Upgrade at https://visa.orizn.app",
  "plan": "free",
  "limit": 50,
  "upgrade_url": "https://visa.orizn.app/visa-api/pricing"
}

Quotas reset on the 1st of the calendar month, UTC.

Bottom line

The Orizn Visa API returns transit information as one field of a broader visa-requirements response — not a standalone "transit visa API." It's genuinely useful for the 44 destinations that carry a hub-level rule (transit-free hours, whether a transit visa is required at that hub), and it is honest about the rest: unmapped destinations, and every rule's inherent limitation to "this airport," not "this passport," come back explicitly as unknown/destination_rule rather than a guessed default. For a product surfacing this to travelers, that distinction — known hub rule vs. "confirm with the carrier" — should stay visible in the UI, because the underlying data draws it that sharply.