Get started
Home Developers API reference
REST Β· v1

VisaCheki API Documentation

AI-powered visa eligibility, requirements, and document review API.


Authentication

All endpoints (except / and /health) require an API key passed as a Bearer token:

Authorization: Bearer vsr_your_key_here

Request a key at [visacheki.com/developers/signup](https://visacheki.com/developers/signup). Keys are issued by hand today, usually within a working day, so tell us what you are building and we can put you on the right tier from the start.


Tiers

TierCalls/monthIncludesPrice
Free100Core endpoints$0
Starter2,000Core endpoints$19/mo
Growth20,000Core endpoints$79/mo
ProUnlimitedBulk check, Data API$299/mo
EnterpriseUnlimitedBulk check, Data API, Compliance API, WebhooksContact us

Every tier is also limited to 60 requests per minute, which is a burst guard rather than a plan feature: it protects the service from a runaway loop and applies the same way whether you are on Free or Enterprise.


Endpoints

GET /v1/countries

Returns all supported countries.

Response:

{
  "countries": [
    { "iso": "NG", "name": "Nigeria", "region": "Africa", "flag": "πŸ‡³πŸ‡¬" },
    { "iso": "GB", "name": "United Kingdom", "region": "Europe", "flag": "πŸ‡¬πŸ‡§" }
  ]
}

GET /v1/origins

Returns countries with at least one outbound visa route: the passports the API can actually run a check from.

Response:

{
  "origins": [
    { "iso": "GH", "name": "Ghana",        "region": "Africa", "flag": "πŸ‡¬πŸ‡­", "route_count": 4 },
    { "iso": "NG", "name": "Nigeria",      "region": "Africa", "flag": "πŸ‡³πŸ‡¬", "route_count": 8 },
    { "iso": "ZA", "name": "South Africa", "region": "Africa", "flag": "πŸ‡ΏπŸ‡¦", "route_count": 2 }
  ]
}

GET /v1/countries/:code/requirements?origin=NG

Returns visa requirements for a specific route.

Example: GET /v1/countries/GB/requirements?origin=NG


POST /v1/check/requirements

Check if a visa is required and what the requirements are.

Request:

{
  "origin": "NG",
  "destination": "GB"
}

Response:

{
  "requirement": {
    "visa_required": true,
    "visa_on_arrival": false,
    "evisa_available": false,
    "fee_usd": 115,
    "processing_days_min": 15,
    "processing_days_max": 90,
    "max_stay_days": 180,
    "entries_allowed": "multiple",
    "documents_required": ["valid_passport", "bank_statements_6_months"],
    "confidence_score": 85,
    "last_verified_at": "2026-05-10T00:00:00.000Z"
  }
}

POST /v1/check/eligibility

Run an AI-powered eligibility assessment based on applicant profile.

Request:

{
  "origin": "NG",
  "destination": "GB",
  "profile": {
    "employment_status": "employed",
    "employer_name": "Starterdot LTD",
    "monthly_income_usd": 2000,
    "bank_balance_usd": 8000,
    "has_property": true,
    "travel_history": ["AE", "RW", "KE"],
    "prior_visa_rejections": [],
    "trip_purpose": "tourism",
    "trip_duration_days": 14,
    "has_invitation_letter": false,
    "has_return_ticket": true,
    "marital_status": "single",
    "dependents": 0
  }
}

Response:

{
  "report_id": "uuid",
  "assessment": {
    "score": 62,
    "risk_level": "medium",
    "verdict": "borderline",
    "flags": [
      {
        "field": "travel_history",
        "issue": "No prior Western country travel history",
        "severity": "medium"
      }
    ],
    "recommendations": [
      "Increase bank balance to at least $10,000 before applying",
      "Obtain a letter from employer confirming your role and salary",
      "Consider applying for UAE or Schengen visa first to build travel history"
    ],
    "summary": "Your application has a moderate chance of approval. The main concerns are limited Western travel history and bank balance slightly below recommended levels for a UK visa."
  }
}

POST /v1/check/documents

Review uploaded documents for issues before submission.

Request:

{
  "origin": "NG",
  "destination": "GB",
  "documents": [
    {
      "type": "passport",
      "content": "Name: Samuel Ayangbola. Expiry: 2027-03-15. Nationality: Nigerian."
    },
    {
      "type": "bank_statement",
      "content": "Average balance last 6 months: $7,200. No large unexplained deposits."
    }
  ]
}

Response:

{
  "review": {
    "verdict": "issues_found",
    "documents": [
      { "type": "passport", "status": "ok", "issues": [], "notes": "Valid, expires well beyond travel window" },
      { "type": "bank_statement", "status": "issue", "issues": ["Balance slightly below Β£5,000 recommended for UK visitor visa"], "notes": null }
    ],
    "missing_documents": ["proof_of_employment", "return_ticket"],
    "critical_issues": [],
    "summary": "Passport is fine. Bank balance is acceptable but could be stronger. Missing employment proof and return ticket."
  }
}

POST /v1/check/cover-letter

Generate a visa application cover letter via AI. Plain text output, suitable for dropping into an editable textarea so the applicant can refine before submission.

Request:

{
  "origin": "NG",
  "destination": "GB",
  "applicant": {
    "name": "Samuel Ayangbola",
    "employment_status": "employed",
    "employer_name": "Starterdot LTD",
    "role_title": "Senior Engineer",
    "monthly_income_usd": 2000,
    "ties_summary": "Wife and two children in Lagos, mortgage on family home, six years at current employer."
  },
  "trip": {
    "purpose": "tourism",
    "start_date": "2026-07-15",
    "end_date":   "2026-07-28",
    "destination_city": "London",
    "sponsor_summary": null
  },
  "prior_visas": "UAE 2023 (granted), Schengen 2024 (granted)"
}

Response:

{
  "origin": "NG",
  "destination": "GB",
  "letter": "[Date]\n\nDear Consular Officer,\n\nI am writing in support of my application for a Standard Visitor Visa to the United Kingdom..."
}

POST /v1/check/interview-prep

Generate a personalised visa-interview study guide. Output is a JSON object with opening_tips[] and a questions[] array, each entry including question, what_they_check, model_answer_outline, and red_flags[]. Together they say what the officer is really probing for and how to answer it candidly.

Request:

{
  "origin": "NG",
  "destination": "GB",
  "applicant": {
    "employment_status": "employed",
    "employer_name": "Starterdot LTD",
    "role_title": "Senior Engineer",
    "ties_summary": "Wife and two children in Lagos, six years at employer."
  },
  "trip": {
    "purpose": "tourism",
    "duration_days": 14,
    "sponsor_summary": null
  },
  "prior_visas": "UAE 2023 (granted), Schengen 2024 (granted)"
}

Response (abbreviated):

{
  "origin": "NG",
  "destination": "GB",
  "prep": {
    "opening_tips": [
      "Have your bank statements and employer letter on top of your file.",
      "Answer in short, specific sentences; volunteer details only when asked."
    ],
    "questions": [
      {
        "question": "Why are you visiting the UK?",
        "what_they_check": "Whether the stated purpose is consistent and the trip is realistic for the duration.",
        "model_answer_outline": "State the specific purpose β€’ name the destination city β€’ outline activities at a high level β€’ mention return date",
        "red_flags": ["Vague or shifting answers", "Hint of intent to extend stay"]
      }
    ]
  }
}

POST /v1/check/full

Runs requirements, eligibility, and document review in a single call.

Request: Combines all fields from the three endpoints above.


Error Codes

CodeMeaning
400Missing or invalid request parameters
401Missing API key, or a key we have no record of
403Your key is real but cannot do this: either it has been disabled, or the endpoint needs a higher tier
404Route not found in database
429Rate limited. Either the 60/minute burst guard or your monthly tier limit
500Internal server error

401 and 403 mean different things, and the difference is worth acting on. A 401 means retrying will not help until you fix the key you are sending. A 403 means the key is genuinely yours and recognised, so the fix is a plan change or a word with us, not a new key. A disabled key returns 403 with a message explaining why and a disabled_at timestamp.

The two 429s are also distinguishable. The burst guard replies {"error": "Too many requests, slow down."} and clears within the minute; the monthly limit replies with your tier, limit, used, and when it resets. Back off on the first, upgrade on the second.


Supported Routes

Two endpoints answer this, and unlike a list in a document they are never out of date:

- GET /v1/origins returns the passport countries we cover. - GET /v1/countries returns the destinations, and GET /v1/countries/:code/requirements?origin=XX tells you whether that particular pair is covered.

Build against those rather than against a hardcoded list. Coverage grows, and a route that is missing today may not be missing next month.

Need a route we do not cover? Email [api@visacheki.com](mailto:api@visacheki.com) and tell us the pair, which helps us prioritise.


Changelog

v0.1.0 - Initial release. 8 Nigeria-origin routes. Requirements, eligibility, and document review endpoints.


Data Licensing API (pro / enterprise)

Expose raw VisaCheki data for embedding in third-party products: travel insurance platforms, corporate travel tools, immigration software, banks.

EndpointTierDescription
GET /v1/data/requirementspro+Bulk visa requirements export
GET /v1/data/changelogpro+Full policy change history
GET /v1/data/processing-statsenterpriseCrowdsourced processing time stats per route
GET /v1/data/outcomesenterpriseAnonymised approval/denial rates per route

GET /v1/data/requirements

Bulk export of all visa requirements. Paginated (max 200 per page).

Query parameters:

ParamTypeDescription
originISO codeFilter by passport country
destinationISO codeFilter by destination country
confidence_mininteger 0–100Only return rows with confidence β‰₯ this value
updated_sinceYYYY-MM-DDOnly rows last verified on or after this date
limitintegerResults per page (max 200, default 100)
offsetintegerPagination offset (default 0)

Response:

{
  "data": [
    {
      "origin_iso": "NG",
      "destination_iso": "GB",
      "visa_required": true,
      "visa_on_arrival": false,
      "evisa_available": false,
      "fee_usd": 115,
      "processing_days_min": 15,
      "processing_days_max": 90,
      "max_stay_days": 180,
      "entries_allowed": "multiple",
      "documents_required": ["passport", "bank_statements", ...],
      "last_verified_at": "2026-05-01",
      "confidence_score": 92,
      "source": "scraped",
      "updated_at": "2026-05-01T10:00:00.000Z"
    }
  ],
  "total": 48,
  "limit": 100,
  "offset": 0,
  "tier": "enterprise"
}

Note: confidence_score and source are only included for enterprise keys.


GET /v1/data/changelog

Full history of visa policy changes. Pro tier returns the last 90 days; enterprise returns the full archive.

Query parameters:

ParamTypeDescription
originISO codeFilter by origin country
destinationISO codeFilter by destination country
sinceYYYY-MM-DDEarliest date to include (enterprise only; pro hard-capped at 90 days)
limitintegerMax 500, default 100
offsetintegerPagination offset

Response:

{
  "data": [
    {
      "origin_iso": "NG",
      "destination_iso": "GB",
      "changed_field": "fee_usd",
      "old_value": "100",
      "new_value": "115",
      "source": "scraper",
      "detected_at": "2026-04-12T08:00:00.000Z"
    }
  ],
  "total": 312,
  "history_cutoff": null,
  "tier": "enterprise"
}

GET /v1/data/processing-stats (enterprise)

Aggregated crowdsourced processing time data per route, split by outcome. Requires at least 3 data points per route.

Response:

{
  "data": [
    {
      "origin_iso": "NG",
      "destination_iso": "GB",
      "total": 47,
      "approved": { "n": 31, "avg_days": 38, "min_days": 12, "max_days": 84 },
      "denied":   { "n": 16, "avg_days": 22, "min_days": 8,  "max_days": 45 }
    }
  ],
  "total": 12
}

GET /v1/data/outcomes (enterprise)

Anonymised approval/denial rates per route, computed from user-reported outcomes. Only routes with β‰₯ 5 reported outcomes are included.

Response:

{
  "data": [
    {
      "origin_iso": "NG",
      "destination_iso": "GB",
      "approved": 31,
      "denied": 16,
      "withdrawn": 2,
      "total": 49,
      "approval_rate_pct": 63.3
    }
  ],
  "total": 10
}