Getting Started
Last verified: 2026-06-20 (Task #389 — Visa Intelligence API docs).
Every public Visa Intelligence endpoint lives under /v1/visa/ and
shares the same authentication scheme, flat error envelope, and
rate-limit headers. Once you can call GET /v1/visa/health, everything
else is a matter of swapping the path and reading the response.
Base URL
| Environment | URL |
|---|---|
| Production | https://api.travelmode.ai |
| Self-hosted Replit deployment | https://your-app-domain.replit.app |
On the api.travelmode.ai host, paths are /v1/visa/.... On a
self-hosted deployment domain the same routes are served under
/api/v1/visa/....
Get an API key
Visa Intelligence is a contracted, customer-facing API. Keys are issued
per tenant from the self-serve dashboard at /visa/account (your
account must be linked to a tenant first — see the
onboarding guide). The
plaintext key is shown exactly once — store it somewhere safe.
A key looks like:
vsk_live_abc123def456ghi789...
See authentication.md for the scope model, the
two ways to send the key, and the customer-vs-key distinction.
Your first request
GET /v1/visa/health needs the visa:health scope and confirms your
key works:
curl -s "https://api.travelmode.ai/v1/visa/health" \
-H "X-Visa-Intel-Key: vsk_live_..."
{
"status": "ok",
"module": "visa-intel",
"version": "1.0.0",
"apiVersion": "v1",
"checks": {
"database": { "status": "ok" },
"sources": { "total": 312, "active": 280, "archived": 32 }
},
"generatedAt": "2026-06-20T12:00:00.000Z"
}
You can also send the key as a bearer token — pick whichever fits your existing HTTP plumbing:
curl -s "https://api.travelmode.ai/v1/visa/health" \
-H "Authorization: Bearer vsk_live_..."
Your first visa check
The headline endpoint resolves visa requirements for a traveler and
destination. It needs the visa:check scope:
curl -s -X POST "https://api.travelmode.ai/v1/visa/check" \
-H "X-Visa-Intel-Key: vsk_live_..." \
-H "Content-Type: application/json" \
-d '{
"nationalityCode": "US",
"destinationCountryCode": "FR",
"purpose": "tourism",
"arrivalDate": "2026-07-01",
"departureDate": "2026-07-12"
}'
{
"status": "ok",
"result": {
"requirement_type": "visa_free",
"summary": "US passport holders can enter France visa-free for stays up to 90 days in any 180-day period.",
"required_actions": [],
"documents": [
{ "name": "Passport", "description": "Valid for at least 3 months beyond departure.", "required": true }
],
"warnings": [],
"confidence": { "level": "high", "reason": "Backed by an official-source-verified rule." },
"sources": [
{
"id": 42,
"authority_name": "France-Visas",
"url": "https://france-visas.gouv.fr/",
"source_type": "government",
"last_checked_at": "2026-06-18T09:00:00.000Z",
"excerpt": "Short-stay (Schengen) visa is not required for US nationals."
}
],
"manual_review_required": false,
"max_stay_days": 90
},
"meta": { "apiVersion": "v1", "moduleVersion": "1.0.0", "generatedAt": "2026-06-20T12:00:00.000Z" }
}
The same call in JavaScript (fetch):
const res = await fetch("https://api.travelmode.ai/v1/visa/check", {
method: "POST",
headers: {
"X-Visa-Intel-Key": process.env.VISA_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
nationalityCode: "US",
destinationCountryCode: "FR",
purpose: "tourism",
}),
});
if (!res.ok) throw new Error(`visa check failed: ${res.status}`);
const { result } = await res.json();
console.log(result.requirement_type); // "visa_free"
Where next
- The full per-endpoint contract is the interactive
API reference (and the raw
openapi.yaml). - Scopes and the customer-vs-key model are in
authentication.md. - Per-key quota and headers are in
rate-limits.md. - Polling changes or subscribing with webhooks is in
changes-webhooks.md. - Every error code is in
errors.md.