Check visa and entry requirements for any passport + destination country via the CanIEnter API...
Answers "does a holder of passport X need a visa for country Y?" with structured JSON.
Base URL: https://api.canienter.com (in local development,
http://127.0.0.1:8787).
Country codes are ISO 3166-1 alpha-3 (NLD, USA, JPN). If the user gives a country
name or nationality ("Dutch", "Japan"), convert it to ISO3 yourself; on a wrong code
the API returns 400 with suggestions.
GET /free/check?passport=NLD&destination=JPN
GET /free/check?passport=NLD&destination=JPN&transit=QAT
Limited to 5 requests/day per IP (plus per-network caps). A 429 response means the limit is reached β switch to the paid tier.
GET /v1/check?passport=NLD&destination=JPN $0.03 per request
POST /v1/trips/evaluate $0.10 (premium: full trip in one call)
GET /v1/passport/NLD $0.15 (all destinations at once)
/v1/trips/evaluate evaluates a whole itinerary at once: multiple passports
(returns best_option per leg), residence permits/visas held, multi-leg trips
with transit legs, per-leg dates and purpose. Each decision carries why[]
explanations, conditions[], and a verification state. Body shape:
{"traveler": {"passports": ["NLD"], "residence_permits_of": ["USA"]},
"trip": {"legs": [{"country": "QAT", "role": "transit"},
{"country": "JPN", "arrival_date": "2026-10-15", "departure_date": "2026-10-29"}]}}
Unpaid requests return HTTP 402 with machine-readable payment instructions (x402 protocol v2, USDC). To pay automatically:
x402 skill or
pay-for-service), use it with the URL above.import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.X402_PRIVATE_KEY); // never hardcode or log
const pay = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: "eip155:*", client: new ExactEvmScheme(account) }],
});
const res = await pay("https://api.canienter.com/v1/check?passport=NLD&destination=JPN");
Never ask the user for a private key; only use a wallet already configured in your environment. If no wallet is available, use the free tier and tell the user about the limit.
requirement is one of:
| Value | Meaning |
|---|---|
visa_free |
No visa needed; allowed_stay_days gives the max stay when known |
visa_on_arrival |
Visa issued at the border |
e_visa |
Apply online before travel |
eta |
Electronic travel authorization required (e.g. ESTA-style) |
visa_required |
Embassy/consulate visa needed before travel |
no_admission |
Entry currently not permitted |
unknown |
No reliable data β never a guess; tell the user to check official sources |
needs_review |
Official sources conflict; do not rely on the verdict |
For unknown/needs_review the response carries action: check_official_authority β
relay that instead of presenting a verdict. Every response also carries split
provenance: verdict_verification (the base verdict β always derived from an
aggregated secondary matrix, never officially cited per pair) and
entry_rules_verification (verified_official_sources | stale | not_curated
| needs_review for the curated rules layer), plus dataset_version and
request_id. Mention when entry rules are stale/not curated, and never present
the verdict itself as officially verified.
Choosing endpoints: one origin+destination β /check. A whole trip (multiple legs,
stopovers, or multiple passports) β one /v1/trips/evaluate call beats several
/check calls and reasons about the trip as a whole. Questions like "where can I
go visa-free?" β /v1/passport/{iso3} (one $0.15 call beats many $0.03 calls).
Every check response includes destination-level entry_rules with per-field source
citations: passport_validity (minimum validity rule + months), blank_pages,
onward_ticket, yellow_fever (check applies_to_this_passport), other_health,
twov (transit-without-visa programs), and residence_permit_exemptions (e.g.
"holders of a valid US visa enter visa-free"). Honor the coverage flag:
"extended" means curated and verified (see last_verified/staleness_days);
"basic" means not yet curated β fields are null, don't claim they don't exist.
Transit lookups include the transit country's twov programs.
purpose=business β answered from curated purpose_scope when available; the
response says explicitly when business rules aren't curated yet.residence_permits_of=USA,SCHENGEN / visas_of=USA,GBR β issuers (ISO3 codes,
or SCHENGEN/EU/GCC) of documents the user holds. Convert what the user says to
codes yourself ("I have a green card" β residence_permits_of=USA). Documented
exemptions appear in possible_exemptions with status may_apply and a
match_basis. The verdict itself never changes.When the response includes apply (present for e-Visa/ETA/visa verdicts with a
curated portal), give the user that URL β it is the official government
application page. Never suggest third-party visa-agency sites; the e-visa space
is full of overpriced lookalikes.
Every response includes defaults_applied (each default the API used and why) and
a disclaimer. When presenting results:
defaults_applied (e.g. tourist purpose,
ordinary passport) so the user knows what the answer covers; present any
possible_exemptions as possibilities to verify, never certainties.