Python SDK

orizn (PyPI)

The official PyPI client. Validates country and language codes before the request leaves your machine, so a typo never costs you quota.

What was executed to write this page

orizn 1.2.0 installed from PyPI into a fresh virtualenv under Python 3.14, then three scripts were run: the quickstart, the error-path script, and the LangChain tool below. Every output block is their real stdout.

Before you start

  • Python 3.9 or later.
  • The final use case also needs langchain-core; it is in the install command below.
  • An Orizn API key. Free tier: 50 requests/month, no credit card — get one at visa.orizn.app/visa-api. It is 5 requests until you confirm your email, so click the link in the confirmation mail.
  • Country codes are ISO 3166-1 alpha-3 — FRA, JPN, USA. Alpha-2 codes (FR, JP) are rejected with a 400, they are not silently converted.
Get a free API key

Walkthrough

1. Install

Terminal
python3 -m venv .venv && source .venv/bin/activate
pip install orizn langchain-core
export ORIZN_API_KEY=orizn_visa_...

2. Your first call — the complete file

quickstart.py
from orizn import Orizn

client = Orizn()  # reads ORIZN_API_KEY

r = client.check("FRA", "JPN")
print(r.requirement)
print(r.visa_free_days)
print(r.last_verified)

visa = client.get_visa("FRA", "JPN", lang="en")
print(visa.description)
print(visa.documents_required)
print(visa.process)
Output · python quickstart.py — real stdout
visa_free
90
2026-05-08
France citizens can enter Japan without a visa for a stay of up to 90 days. A valid passport is required.
['Valid passport (6 months minimum)', 'Return or onward ticket', 'Proof of accommodation', 'Proof of sufficient funds']
['No prior formalities required', 'Present valid passport upon arrival', 'Entry stamp will be issued at border control']

3. Close the session

The client holds an HTTP session. Use it as a context manager in anything long-lived.

with Orizn() as client:
    print(client.check("DEU", "BRA").requirement)

4. The four methods

  • check(passport, destination) — requirement, visa-free days, last_verified.
  • get_visa(passport, destination, lang="en") — the full record.
  • bulk(passport, destinations, lang="en") — up to 25 destinations, Hobby plan and above.
  • stats() — coverage, no key needed.

When it goes wrong

Every failure the integration can hand you, with the message it actually prints.

No key anywhere

OriznAuthError
Orizn: an API key is required.
  Get a free one in 10 seconds (50 req/month, 15 languages): https://visa.orizn.app/visa-api
  Then: Orizn(api_key="orizn_visa_...") or export ORIZN_API_KEY=...

A matching three-line hint is printed to stderr at construction, before the call fails.

Key unknown, or plan too low for the endpoint

OriznForbiddenError
Invalid API key — Get your free API key at https://visa.orizn.app/visa-api
Orizn: this key cannot make this call (invalid key, or plan too low).
  Check or create a key: https://visa.orizn.app/visa-api
  Unlock it (Hobby, $9/mo, 10,000 req): ...

403 is overloaded: it is either a bad key or a good key on too small a plan. The message distinguishes them.

check("FR", "JP") — alpha-2 codes

ValueError, raised before the request
passport must be a 3-letter ISO 3166-1 alpha-3 code (FRA, JPN, USA) — got 'FR'

This is deliberate: the API bills a request before validating parameters, so client-side validation protects your quota.

check("FRA", "XXX") — valid shape, no record

OriznNotFoundError
Orizn: no visa data for FRA → XXX. Both must be ISO 3166-1 alpha-3 codes (FRA, JPN, USA).

Treat as unknown, never as visa-free.

Monthly quota spent

OriznRateLimitError
Carries retry_after when the API sends it.

All four subclass OriznError, which also covers timeouts and connection failures — catch that at the outer edge.

The auth, forbidden, ValueError and not-found rows are verbatim stdout from a script that triggered each case. The rate-limit row was not reproduced: the key used to write this page is uncapped.

End to end: a LangChain tool that will not hallucinate

The reason most people reach for this SDK is to stop a model inventing entry rules. Ten lines gets you a tool whose docstring is the instruction the model actually reads.

agent_tool.py
from langchain_core.tools import tool
from orizn import Orizn, OriznError

client = Orizn()  # reads ORIZN_API_KEY


@tool
def check_visa(passport: str, destination: str) -> str:
    """Check the visa requirement between two countries, using ISO 3166-1 alpha-3 codes
    (e.g. FRA, JPN, USA). Use for any "do I need a visa / how long can I stay" question.
    Never answer from memory."""
    try:
        r = client.check(passport.upper(), destination.upper())
    except (OriznError, ValueError) as e:
        return f"Lookup failed: {e}"
    out = f"{r.passport} -> {r.destination}: {r.requirement}"
    if r.visa_free_days:
        out += f" ({r.visa_free_days} days)"
    if r.last_verified:
        out += f" [verified {r.last_verified}]"
    return out


if __name__ == "__main__":
    print(check_visa.invoke({"passport": "BRA", "destination": "JPN"}))
    print(check_visa.invoke({"passport": "IND", "destination": "THA"}))
    print(check_visa.invoke({"passport": "FRA", "destination": "XX"}))
Output · python agent_tool.py — real stdout
BRA -> JPN: visa_free (90 days) [verified 2026-05-08]
IND -> THA: visa_free (30 days) [verified 2026-08-05]
Lookup failed: destination must be a 3-letter ISO 3166-1 alpha-3 code (FRA, JPN, USA) — got 'XX'

Note the third line. The failure is returned as text rather than raised, so the model sees what went wrong and can correct the code itself — a raised exception just kills the run. Drop the tool into create_react_agent alongside your model and you are done.

Source & reference

Other integrations

50 requests a month, no credit card

All 15 languages included on the free plan. Hit a wall with this tutorial? Mail [email protected] — a tutorial that does not work is a bug.