orizn
Official Python SDK for the Orizn Visa API.
Visa requirements for 40,027 passport-destination pairs, in 15 languages, with up to 32 data points per visa — fees, processing times, photo specs, transit visas, embassies, overstay penalties, safety advisories.
Install
pip install orizn
Quick start
from orizn import Orizn
# Free key, 10 seconds, no credit card → https://visa.orizn.app/visa-api
client = Orizn(api_key="orizn_visa_...") # or: export ORIZN_API_KEY=...
r = client.check("FRA", "JPN")
print(r.requirement) # "visa_free"
print(r.visa_free_days) # 90
visa = client.get_visa("USA", "CHN", lang="fr") # all 15 languages, free plan included
print(visa.description)
print(visa.documents_required)
print(visa.process)
That runs as-is once ORIZN_API_KEY is set. Every visa endpoint needs a key — the free
tier is 100 requests/month (5 until you confirm your email).
Get a key
| Free key, instant | https://visa.orizn.app/visa-api |
| Upgrade to Starter — $49/mo, 30,000 req | billing |
| Plan | Price | Requests/month |
|---|---|---|
| Free | $0 | 100 |
| Starter | $49 | 30,000 |
| Pro | $199 | 250,000 |
| Business | $699 | 1,000,000 |
All 15 languages are available on every plan, free included. What paid plans add is volume and the extended data points (fees, transit, embassies, safety, …).
Methods
| Method | Auth | Description |
|---|---|---|
check(passport, destination) |
Key | Requirement, visa-free days, last-verified date |
get_visa(passport, destination, lang="en") |
Key | Full record — up to 32 data points |
bulk(passport, destinations, lang="en") |
Key (Starter+) | Up to 25 destinations in one call |
stats() |
None | Public coverage statistics |
bulk() requires an explicit list of destinations (max 25 per call), and each destination
returned counts as one request against your quota.
for row in client.bulk("FRA", ["JPN", "USA", "THA"]):
print(row.destination, row.requirement, row.visa_free_days)
The client is a context manager, so the HTTP session gets closed:
with Orizn() as client:
print(client.check("DEU", "BRA").requirement)
Errors
Four typed exceptions, each carrying the URL that unblocks you:
from orizn import OriznAuthError, OriznForbiddenError, OriznRateLimitError, OriznNotFoundError
try:
visa = client.get_visa("FRA", "JPN")
except OriznAuthError: # 401 — no key. Message links to the free key page.
...
except OriznForbiddenError: # 403 — invalid key, or plan too low for this call.
...
except OriznRateLimitError as e: # 429 — quota spent. e.retry_after when the API sends it.
...
except OriznNotFoundError: # 404 — no data for that pair.
...
All four subclass OriznError, which also covers timeouts and connection failures.
Bad country codes and unsupported languages raise ValueError before the request goes out —
the API bills a request before validating params, so a typo would otherwise cost you quota.
What's in get_visa()
Fields your plan doesn't include come back as None.
Core (always present)
| Field | Type | Description |
|---|---|---|
passport / destination |
str |
ISO 3166-1 alpha-3 |
requirement |
VisaRequirement |
visa_free | visa_required | e_visa | visa_on_arrival | eta | no_admission |
visa_free_days |
int | None |
Max visa-free stay, in days |
visa_required |
bool |
True if any visa formality applies |
description |
str |
Localized summary |
documents_required |
list[str] |
Documents to bring/submit |
process |
list[str] |
Step-by-step application process |
tips |
list[str] |
Travel tips |
visa_types |
list[VisaType] |
Visa categories available — name, cost, duration, description |
extension, processing_time, cost, validity, max_stay |
str | None |
Localized free-text details |
country_info |
CountryInfo |
Currency, language, timezone, capital |
verified |
bool |
Verified against an official source |
source |
str | None |
Where the record came from |
plan, remaining |
str | int | None |
Your plan and requests left, read from the response headers |
Extended intelligence (plan-gated)
| Field | Type | What it tells you |
|---|---|---|
transit_visa |
TransitVisa |
Transit rules + free transit hours at major hubs (DXB, IST, DOH, SIN, …) |
passport_validity_months |
int |
Minimum passport validity at entry |
visa_fee |
VisaFee |
Single- and multiple-entry cost, with currency |
processing_days |
ProcessingDays |
Standard / express / rush |
photo_specs |
PhotoSpecs |
Dimensions, background, glasses & head-covering rules |
vaccinations_required |
list[str] |
Mandatory vaccines |
insurance_required |
InsuranceRequired |
Minimum travel insurance coverage |
dual_nationality_warnings |
list[str] |
Warnings for dual nationals |
stamp_warnings |
list[str] |
Passport stamps that may block entry |
minor_rules |
MinorRules |
Rules for under-18s |
overstay_penalty |
OverstayPenalty |
Fine per day, max fine, criminal liability, and ban_duration — days keyed by scenario ({"under_30_days": 365, …}), since the API has no single number |
entry_by_mode |
EntryByMode |
air / land / sea, each the API's raw object (visa_free_days, esta_required, e_visa_available, … — the keys vary by pair) |
remote_work_visa |
RemoteWorkVisa |
Digital nomad visa availability, duration, fee |
extension_rules |
ExtensionRules |
Whether the stay can be extended, and how |
reciprocity_history |
list[ReciprocityChange] |
Past policy changes between the two countries |
safety |
SafetyInfo |
Advisory level (1–4), source, last update |
best_apply_period |
str |
Recommended application window |
health_requirements |
HealthRequirements |
Tests, vaccination proof, quarantine, screenings |
embassy |
EmbassyData |
Two lists of EmbassyInfo: your missions at the destination, and the destination's missions in your country (a country usually has an embassy plus consulates) |
visa = client.get_visa("FRA", "JPN")
if visa.visa_fee and visa.visa_fee.single_entry:
fee = visa.visa_fee.single_entry
print(f"Single entry: {fee.amount} {fee.currency}")
if visa.transit_visa:
for hub in visa.transit_visa.hubs:
print(f"{hub.airport} ({hub.city}): {hub.transit_free_hours}h transit-free")
if visa.safety:
print(f"Advisory level: {visa.safety.level}")
if visa.embassy:
for e in visa.embassy.visa_application_embassy: # where to apply
print(f"{e.name} ({e.city}) — {e.phone}")
print(visa.entry_by_mode.air.get("visa_free_days") if visa.entry_by_mode else None)
All types are exported: from orizn import VisaData, TransitVisa, EmbassyData, ....
Languages
fr en es pt de it ja ko zh ru ar hi th vi tl — the tuple is exported as orizn.LANGUAGES.
Tests
python tests/test_client.py # offline, no key
ORIZN_API_KEY=... python tests/test_client.py # + a live smoke test (~5 requests)
Offline, a fake session replays payloads captured from production. With a key set, the same
run also hits the real API, so a schema drift shows up instead of silently decoding to None.
Feedback
Building a travel agent or visa tool? Tell us what you need — api@orizn.app.
Links
Metadata
Release files for orizn 1.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| orizn-1.2.1.tar.gz | 20.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| orizn-1.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.4 kB
Release files / orizn-1.2.1.tar.gz
| Download URL | orizn-1.2.1.tar.gz |
|---|---|
| Size | 20.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
97e1b9de5c1bd0b95b3d194f1bf21ad47cf3afa456cece967c5444b82aa59998
|
|
BLAKE2b-256 checksum How to use checksums |
d31e221da578524075bec2338612040c88da0a2a371095d89f02ff601c4f55ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Release files / orizn-1.2.1-py3-none-any.whl
| Download URL | orizn-1.2.1-py3-none-any.whl |
|---|---|
| Size | 16.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
073012e8e070e61db839b259a44bb6a22faf4cf08632a382655ecd579272444d
|
|
BLAKE2b-256 checksum How to use checksums |
2618498c9918f9705ebdb925e705be120f5c5d0a9db6beae4cb29872ea2a3b1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|