Developer Documentation
Integrate global visa requirements and passport mobility data into your application.
What's new
v1.7.0 — Structured currency & fee parsing. New currencies + exchange_rates tables (USD-base, lazy-refreshed from exchangerate-api.com on 24h staleness). All fee strings parsed into fee_amount, fee_amount_max, fee_currency columns on both visa_info and visa_info_types (98%+ extraction rate). Responses now include a fee.structured object with numeric amounts, USD equivalent, range support, and conversion to any currency via ?currency=XXX. New /currencies.php endpoint lists supported codes + current rates. Requires migration_currency.sql + backfill_currency.php.
v1.6.0 — Regional & grouping metadata. New countries + country_groups tables with 249 countries (continent + UN M.49 subregion) and 20 travel-relevant blocs (Schengen, GCC, ASEAN, SAARC, EU, NATO, BRICS+, US VWP, ETIAS, etc.). /visa-details now embeds region + groups on both passport and destination. /country-profile, /countries-list, and /visiting-countries support new continent, subregion, and group filter params. New /groups.php endpoint lists all blocs with members. Requires migration_regions_groups.sql.
v1.5.2 — Structured photo specifications: /visa-details now returns a parsed passport_requirements.photo object with width_mm, height_mm, background_color, biometric, digital_accepted, max_age_months, country_spec, and notes. Free-text photo_specifications remains for backward compat. Optional SQL migration available to persist the parsed fields as queryable columns.
v1.5.1 — Optional visa_types filter parameter on /visa-details: narrow the visa_types[] array to specific categories (e.g. ?visa_types=Business,Work). Response meta now includes visa_types_available listing every category present for the destination, so clients can self-discover what to request.
v1.5.0 — Structured visa types: each /visa-details response now includes a visa_types[] array exposing Tourist, Business, Transit, Student, Work, and other categories with their own fees, validity, application workflow, and approval signals. New endpoint /passport-compare.php for side-by-side comparison of 2-10 passports.
v1.4.0 — New endpoint /passport-strength.php: aggregate mobility metrics, rank vs other passports, fee statistics, and lists of visa-free / visa-on-arrival destinations.
v1.3.0 — 15 structured fields on /visa-details (entry type, application center, appointment, urgent processing, interview, approval rate, extension, overstay penalty, transit visa, data confidence, verification date). Migration: validity_max_stay → stay.*, timestamps → meta.*.
Country Profile UPDATED v1.6.0
Returns a summary of visa requirements for all visiting countries from the perspective of the given passport. v1.6.0 adds region/group filtering and embeds region + groups on passport and each destination.
Parameters
| Param | Type | Description |
|---|---|---|
passport_country_iso2 | String | Required. 2-letter ISO 3166-1 alpha-2 (e.g. BD). |
continent NEW v1.6.0 | String | Optional. Filter destinations by continent: AfricaAmericasAsiaEuropeOceaniaAntarctica |
subregion NEW v1.6.0 | String | Optional. Filter by UN M.49 subregion. E.g. "Southern Asia", "Western Europe", "Eastern Africa". Get the full list via /countries-list.php?type=subregions. |
group NEW v1.6.0 | String | Optional. Filter by country-group code(s), comma-separated. E.g. schengen, gcc,asean, us_vwp. Run /groups.php to discover valid codes. |
currency NEW v1.7.0 | String | Optional. ISO 4217 code to convert all destination fees to. E.g. ?currency=GBP. |
Example Requests
# All destinations GET /country-profile.php?passport_country_iso2=BD # Only European destinations GET /country-profile.php?passport_country_iso2=BD&continent=Europe # Only Schengen destinations (single visa enters 29 states) GET /country-profile.php?passport_country_iso2=BD&group=schengen # Multiple groups — destinations in GCC OR ASEAN GET /country-profile.php?passport_country_iso2=BD&group=gcc,asean
Visa Details UPDATED v1.7.0
Returns the complete visa profile for a passport-destination pair. Includes embassy contacts, structured requirement flags, application workflow, fees, stay rules, data quality signals, a visa_types[] array exposing each visa category, and (as of v1.5.2) a structured passport_requirements.photo object with parsed dimensions, background, biometric/digital flags, and country-specific notes.
Parameters
| Param | Type | Description |
|---|---|---|
passport_country_iso2 | String | Required. Origin passport (e.g., BD). |
visiting_country_iso2 | String | Required. Destination country (e.g., AE). |
visa_types v1.5.1 |
String |
Optional. Comma-separated list of visa categories to return in the visa_types[] array. Case-insensitive. Filters only the visa_types[] array — legacy top-level blocks (overview, application, fees, stay) always reflect the Tourist primary record for backward compatibility.Allowed values: TouristBusinessTransitStudentWorkFamilyMedicalConferenceJournalistDiplomaticCreweVisaVoAVisa-FreeOther |
currency NEW v1.7.0 | String | Optional. ISO 4217 currency code (e.g. EUR, GBP, JPY, USD). When supplied, all fees include amount_in_requested with the converted amount. See /currencies.php for valid codes. |
Example Requests
# All visa types (default) GET /visa-details.php?passport_country_iso2=BD&visiting_country_iso2=AE # Filter to a single visa type GET /visa-details.php?passport_country_iso2=BD&visiting_country_iso2=US&visa_types=Business # Filter to multiple GET /visa-details.php?passport_country_iso2=BD&visiting_country_iso2=US&visa_types=Business,Student,Work
Self-discovery via response meta
The response meta always includes visa_types_available — an alphabetical list of every visa category present for the destination. Use this to populate filter chips/dropdowns without trial and error.
When the visa_types filter is applied, meta.visa_types_filter echoes the normalized values that were actually used (after deduplication and canonical casing).
Response shape (full)
{
"success": true,
"meta": {
"generated_at": "2026-05-16T01:55:00+00:00",
"visa_type_count": 1,
"visa_types_available": ["Business", "Tourist", "Transit"], // NEW v1.5.1 — always present
"visa_types_filter": ["Business"] // NEW v1.5.1 — only when filter applied
},
"data": {
"id": 99,
"passport": { "country": "Bangladesh", "iso2": "BD", "currency_code": "BDT" },
"destination": { "country": "United Arab Emirates", "iso2": "AE" },
"overview": {
"visa_fees_summary": "...",
"visa_types": "...", // free-text legacy summary
"govt_portal_url": "https://...",
"entry_type": "Single",
"approval_rate_estimate": "Medium",
"transit_visa_required": "Conditional"
},
"embassy": {
"address": "...", "map_url": "https://...",
"phone": "+880 2 ...", "email": "..."
},
"passport_requirements": {
"passport_validity": "6+ months from entry",
"photo_specifications": "35x45mm, white bg", // raw, kept for compat
"photo": { // NEW v1.5.2 — structured
"raw": "35x45mm, white bg",
"required": "Yes",
"width_mm": 35, "height_mm": 45,
"alt_dimensions": null,
"background_color": "White",
"biometric": false,
"digital_accepted": false,
"digital_only": false,
"max_age_months": null,
"country_spec": null
},
"required_documents": "..."
},
"requirements": { ... },
"application": { // ← Primary (Tourist) cache for compat
"method": "Embassy via VFS Dhaka",
"center_type": "VFS Global",
"processing_time": "15 working days",
"appointment": { "required": "Yes", "booking_url": "..." },
"interview": { "required": "Conditional" },
"urgent_processing": { "available": "No", "details": null }
},
"fees": { ... }, // ← Primary (Tourist) cache
"stay": { ... }, // ← Primary (Tourist) cache
"rejection_reasons": "...",
"visa_types": [ // NEW v1.5 — structured array
{
"visa_type": "Tourist",
"visa_subtype": null,
"is_primary": true,
"entry_type": "Single",
"validity": null,
"max_stay": "Validity: 60 days from issue. Max Stay: 30 days...",
"extension_possible": "Conditional",
"fee": {
"local_currency": "AED 350",
"usd": "USD 95",
"passport_currency": "BDT 11,615",
"service_fee_note": "VFS service fee: USD 25-40 on top of visa fee"
},
"application": {
"method": "Embassy via VFS Dhaka",
"center_type": "VFS Global",
"processing_time": "15 working days",
"appointment": { "required": "Yes", "booking_url": "..." },
"interview": { "required": "Conditional" },
"urgent_processing": { "available": "No", "details": null }
},
"minimum_bank_balance_usd": "USD 100/day",
"approval_rate_estimate": "Medium",
"summary": "Tourist visa for leisure visits...",
"notes": null,
"meta": { "data_confidence": "High", "last_verified_at": "2026-05-15", ... }
}
/* additional types (Business, Transit, Student, etc.) appended here */
],
"meta": {
"data_confidence": "High",
"last_verified_at": "2026-05-15",
"created_at": "2026-05-13 02:57:48",
"updated_at": "2026-05-15 00:18:11"
}
}
}visa_types[] field reference NEW v1.5.0
Each element in the array represents one visa category for the passport-destination pair. The element marked is_primary=true (usually Tourist) duplicates the top-level application / fees / stay blocks for backward compatibility.
| Field | Type | Description |
|---|---|---|
visa_type |
enum | TouristBusinessTransitStudentWorkFamilyMedicalConferenceJournalistDiplomaticCreweVisaVoAVisa-FreeOther |
visa_subtype |
string nullable | Specific category, e.g., "Schengen Type C", "B1/B2", "ETA", "90-day Multi-Entry". |
is_primary |
boolean | True for the most-common/default visa type per pair (usually Tourist). The legacy top-level application / fees / stay blocks reflect the primary type. |
fee.local_currency / fee.usd / fee.passport_currency |
string | Type-specific fees. Different visa types (Tourist vs Business) often have very different fees. |
application.* |
object | Type-specific application workflow (method, processing time, appointment, interview, urgent processing). |
summary / notes |
string | Type-specific summary and gotchas (e.g., sponsor letter for Business, course acceptance for Student). |
passport_requirements.photo field reference NEW v1.5.2
The photo object is parsed from the free-text photo_specifications string. The raw value is preserved under passport_requirements.photo_specifications for backward compatibility; the parsed object is the recommended way to consume photo requirements going forward.
| Field | Type | Description |
|---|---|---|
raw | string | The original free-text value (same as photo_specifications). |
required | enum | YesNo — No for visa-free, on-arrival, citizen, EASE, etc. |
width_mm / height_mm | float nullable | Photo dimensions normalized to millimeters. Source values in cm or inches are auto-converted (e.g., 2x2 inch → 50.8 × 50.8 mm, 4x5cm → 40 × 50 mm). May be null for underspecified entries like "Color, white bg". |
alt_dimensions | string nullable | Alternative acceptable dimensions when the source lists two (e.g., "30x40mm or 50x50mm, white bg" → "50x50mm"). |
background_color | enum | WhiteOff-whiteLight blue or null. |
biometric | boolean | true when the source says "biometric" — typically Schengen, UK, etc. |
digital_accepted | boolean | true when digital uploads (eVisa/ETA) are accepted. |
digital_only | boolean | true when only digital is supported (e.g. "Digital (for ETA)", standalone "Digital"). Implies digital_accepted = true. |
max_age_months | int nullable | Photo must be newer than N months. Parsed from "last 6 months" / "not older than 6 months". |
country_spec | string nullable | Country/format spec label captured from parentheticals: "US spec", "Japan spec", "Indian spec", "ICAO standard", "Chinese spec", etc. |
notes | string[] | Conditional notes — "Hijab required for women", "No glasses", "ICAO standard", "Natural color", "Recent photo required", etc. Omitted from response if empty. |
Parsing notes
"Passport size" / "Passport-style" without explicit dimensions defaults to 35 × 45 mm (the BD/global standard) with a corresponding note added.
The parser is forgiving — even when only background or color info is available, the structured object is still returned with the fields that could be extracted. Dimensions remain null in those cases.
Original free-text remains under passport_requirements.photo_specifications. The two fields will always be consistent — photo.raw equals photo_specifications.
Field reference — added in v1.3.0
| Field | Type | Description |
|---|---|---|
overview.entry_type | enum | SingleDoubleMultipleVisa-FreeVoAN/A |
overview.approval_rate_estimate | enum | HighMediumLowUnknown |
overview.transit_visa_required | enum | YesNoConditionalN/A |
application.center_type | enum | EmbassyVFS GlobalBLS InternationalTLScontactDirect OnlineVoAVisa-FreeMixedOther |
application.appointment.required | enum | YesNoConditionalN/A |
application.interview.required | enum | YesNoConditionalN/A |
application.urgent_processing.available | enum | YesNoN/A |
fees.minimum_bank_balance_usd | string nullable | Funds proof requirement, normalized to USD. |
fees.service_fee_note | string nullable | Additional service-center fee beyond visa fee (typ. USD 20-40 for VFS/BLS/TLS). |
stay.extension_possible | enum | YesNoConditionalN/A |
stay.overstay_penalty | text nullable | Penalty for overstaying (per-day fines, bans, etc). |
meta.data_confidence | enum | HighMediumLow |
meta.last_verified_at | date nullable | ISO date when a human last confirmed this row. |
Filter behavior v1.5.1
| Scenario | Behavior |
|---|---|
visa_types omitted | Returns all visa categories present for the destination. |
visa_types=Business | Returns only Business rows in the visa_types[] array. |
visa_types=Business,Student | Returns rows matching either category. Order: is_primary DESC, visa_type ASC, visa_subtype ASC. |
Case variations (business, BUSINESS) | Normalized to canonical casing. Echoed in meta.visa_types_filter. |
Duplicates (Business,business) | Deduplicated. |
Empty (visa_types=) or commas only | Treated as no filter — all types returned. |
| Filter matches nothing | Not a 404. Returns 200 with empty visa_types[]. |
Invalid value (e.g. Bogus) | Returns 400 INVALID_VISA_TYPE. |
| Legacy top-level fields | Always reflect Tourist primary record — never affected by the filter. |
Passport Strength
Returns an aggregate mobility profile for a passport: how many destinations are visa-free vs require advance application, fee statistics across all destinations, application workflow distribution, approval-rate counts, data-quality counts, and the passport's rank versus all other supported passports.
Parameters
| Param | Type | Description |
|---|---|---|
passport_country_iso2 | String | Required. 2-letter ISO 3166-1 alpha-2 code (e.g., BD). |
Example Request
Response shape
{
"data": {
"passport": { "country": "Bangladesh", "iso2": "BD", "currency_code": "BDT" },
"total_destinations": 203,
"score": {
"mobility_score": 27,
"rank": 7,
"rank_of_total": 10,
"rank_method": "visa_free + visa_on_arrival count"
},
"mobility": {
"visa_free": 18, "visa_on_arrival": 9,
"no_advance_visa": 27, "visa_required": 175,
"own_country": 1,
"visa_free_percentage": 8.9,
"open_access_percentage": 13.3
},
"entry_type_breakdown": { "Single": 138, "Multiple": 37, ... },
"approval_rate_distribution": { "High": 26, "Medium": 167, "Low": 10, "Unknown": 0 },
"application_workflow": {
"centers": { "Embassy": 53, "VFS Global": 44, ... },
"appointment_required_count": 93,
"interview_required_count": 1,
"urgent_processing_available_count": 2,
"extension_possible_count": 25,
"transit_visa_required_count": 3
},
"fees": {
"average_usd": 87.5, "median_usd": 75,
"min_usd": 0, "max_usd": 300,
"free_count": 27, "sample_size": 202
},
"data_quality": { "high_confidence": 53, "medium_confidence": 136, "low_confidence": 14 },
"visa_free_destinations": [ {"iso2": "BS", "country": "Bahamas"}, ... ],
"visa_on_arrival_destinations": [ {"iso2": "BJ", "country": "Benin"}, ... ]
}
}Passport Compare NEW v1.5.0
Compares 2-10 passports side-by-side. Returns per-metric value maps, a winners block highlighting the best passport per metric (with tie support), and set operations on destinations: common visa-free destinations across ALL compared passports, and destinations unique to each.
Parameters
| Param | Type | Description |
|---|---|---|
codes | String | Required. Comma-separated 2-letter ISO codes, 2-10 passports (e.g., BD,IN,PK). Duplicates are deduped. |
Example Request
Response shape
{
"meta": {
"generated_at": "...",
"compared_count": 3,
"rank_method": "visa_free + visa_on_arrival count"
},
"data": {
"compared_passports": [
{ "country": "Bangladesh", "iso2": "BD", "currency_code": "BDT",
"mobility_score": 27, "global_rank": 7, "rank_of_total": 10 },
{ "country": "India", "iso2": "IN", "currency_code": "INR",
"mobility_score": 53, "global_rank": 3, "rank_of_total": 10 },
{ "country": "Pakistan", "iso2": "PK", "currency_code": "PKR",
"mobility_score": 8, "global_rank": 10, "rank_of_total": 10 }
],
"comparison": {
"mobility_score": { "BD": 27, "IN": 53, "PK": 8 },
"visa_free": { "BD": 18, "IN": 27, "PK": 6 },
"visa_on_arrival": { "BD": 9, "IN": 26, "PK": 2 },
"no_advance_visa": { "BD": 27, "IN": 53, "PK": 8 },
"average_fee_usd": { "BD": 87.5, "IN": 75.2, "PK": 102.4 },
"high_approval_destinations": { "BD": 26, "IN": 58, "PK": 35 },
"low_approval_destinations": { "BD": 10, "IN": 12, "PK": 47 },
"appointment_required_count": { "BD": 93, "IN": 89, "PK": 106 }
/* ... more metrics */
},
"winners": {
"highest_mobility_score": ["IN"],
"most_visa_free": ["IN"],
"cheapest_average_fee": ["IN"],
"fewest_low_approval_destinations": ["BD"]
/* always arrays — supports ties */
},
"visa_free_destinations": {
"common_to_all": [
{ "iso2": "BB", "country": "Barbados" }
],
"unique_per_passport": {
"BD": [ { "iso2": "BS", "country": "Bahamas" } ],
"IN": [ { "iso2": "TT", "country": "Trinidad and Tobago" } ],
"PK": []
}
},
"per_passport_detail": {
"BD": { /* full strength aggregation */ },
"IN": { /* ... */ },
"PK": { /* ... */ }
}
}
}Notes
Winners are arrays. When multiple passports tie on a metric (e.g., both have zero interviews required), all tied codes appear in the array. Client code can safely treat as a list of length 1+.
Rank stays global. The global_rank on each compared passport is its position across all 10 supported passports — not the position within the subset you're comparing. So comparing BD vs PK still shows BD=7 and PK=10.
Countries List
Fetches the distinct list of countries supported by the system. Useful for populating dropdowns.
Parameters
| Param | Type | Description |
|---|---|---|
type | String | Optional. One of: all (default), passport, visiting. |
Example Request
Visiting Countries List
Returns countries available for visiting. If a passport code is provided, the list is filtered to only countries reachable by that passport — useful for cascading dropdowns.
Parameters
| Param | Type | Description |
|---|---|---|
passport_country_iso2 | String | Optional. Returns only countries reachable by this passport. |
Example Request
Enum Field Reference
Quick reference for the structured ENUM values used across the API.
| Enum | Values | Notes |
|---|---|---|
visa_type | TouristBusinessTransitStudentWorkFamilyMedicalConferenceJournalistDiplomaticCreweVisaVoAVisa-FreeOther | Categories within visa_types[]. |
entry_type | SingleDoubleMultipleVisa-FreeVoAN/A | VoA = Visa on Arrival. N/A for own-country. |
application_center_type | EmbassyVFS GlobalBLS InternationalTLScontactDirect OnlineVoAVisa-FreeMixedOther | Mixed = multiple application channels. |
appointment_required / interview_required / extension_possible / transit_visa_required | YesNoConditionalN/A | Conditional = depends on visa category or applicant profile. |
urgent_processing_available | YesNoN/A | N/A for visa-free. |
approval_rate_estimate | HighMediumLowUnknown | Derived from documented rejection patterns. Not a guarantee. |
requirements.*.status | YesNoConditionalRecommendedMandatoryN/A | Granular requirement status. |
data_confidence | HighMediumLow | Internal trust signal. |
Error Responses
All errors follow a consistent shape. Inspect error.code programmatically.
{
"success": false,
"error": {
"code": "INVALID_ISO2",
"message": "Invalid passport_country_iso2: must be a 2-letter ISO 3166-1 alpha-2 code (e.g. BD, PK, US)."
}
}Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | MISSING_PARAM | A required query parameter was omitted. |
| 400 | INVALID_ISO2 | Country code is not a valid 2-letter ISO 3166-1 alpha-2. |
| 400 | SAME_COUNTRY | Passport and visiting country are identical. |
| 400 | INVALID_TYPE | The type parameter is not one of the allowed values. |
| 400 | INVALID_CURRENCY NEW v1.7.0 | The currency parameter is not a 3-letter alphabetic ISO 4217 code. |
| 400 | UNSUPPORTED_CURRENCY NEW v1.7.0 | The currency value is a valid ISO format but isn't in the currencies catalog. See /currencies.php. |
| 404 | CURRENCY_NOT_FOUND NEW v1.7.0 | Returned by /currencies.php?code=XXX when no matching currency exists. |
| 400 | INVALID_CONTINENT NEW v1.6.0 | The continent parameter is not one of: Africa, Americas, Asia, Europe, Oceania, Antarctica. |
| 400 | INVALID_SUBREGION NEW v1.6.0 | The subregion value is not a known UN M.49 subregion. See /countries-list.php?type=subregions. |
| 400 | INVALID_GROUP NEW v1.6.0 | One or more values in the group parameter is not a recognized group code. See /groups.php. |
| 500 | MIGRATION_NOT_APPLIED NEW v1.6.0 | Returned by region/group endpoints when migration_regions_groups.sql has not been applied. Run the migration to enable. |
| 404 | GROUP_NOT_FOUND NEW v1.6.0 | The code requested in /groups.php does not exist. |
| 400 | INVALID_VISA_TYPE v1.5.1 | One or more values in the visa_types parameter is not a valid visa category. |
| 400 | INSUFFICIENT_CODES | Fewer than 2 codes supplied to /passport-compare.php. |
| 400 | TOO_MANY_CODES | More than 10 codes supplied to /passport-compare.php. |
| 404 | PASSPORT_NOT_FOUND | No data for the specified passport country. |
| 404 | VISA_RECORD_NOT_FOUND | No data for the specified passport-destination pair. |
| 405 | METHOD_NOT_ALLOWED | Use GET; other methods rejected. |
| 500 | MIGRATION_NOT_APPLIED | v1.3 schema columns missing — run migration scripts first. |
| 500 | DB_CONNECTION_ERROR | Internal database connection failed. Retry later. |
Country Groups NEW v1.6.0
Lists all 20 country groups (Schengen, GCC, ASEAN, SAARC, EU, Eurozone, NATO, BRICS+, US VWP, ETIAS, EAC, CARICOM, Arab League, Commonwealth, G7, G20, OPEC, EFTA, CIS, Mercosur) with their members and metadata. Useful for populating filter dropdowns or displaying group memberships in client UIs.
Parameters
| Param | Type | Description |
|---|---|---|
code | String | Optional. Return only this group (e.g. schengen). When set, the response is a single group object (not a list). |
category | String | Optional. Filter by category: politicaleconomicvisa-bloccustom |
include | String | Optional. members to include the full member list (default for single-code request). count for member count only (default for list request). |
Example Requests
# List all 20 groups with member counts GET /groups.php # Only visa-bloc category (Schengen, GCC, ASEAN, CARICOM, EAC, US VWP, ETIAS) GET /groups.php?category=visa-bloc # Single group with full member list GET /groups.php?code=schengen
The 20 country groups
| Category | Code | Name | Members |
|---|---|---|---|
| visa-bloc | schengen | Schengen Area | 29 |
| visa-bloc | gcc | Gulf Cooperation Council | 6 |
| visa-bloc | asean | ASEAN | 10 |
| visa-bloc | caricom | CARICOM | 15 |
| visa-bloc | eac | East African Community | 7 |
| visa-bloc | us_vwp | US Visa Waiver Program | 40 |
| visa-bloc | etias | ETIAS (EU pre-authorization) | 58 |
| political | eu | European Union | 27 |
| political | saarc | SAARC | 8 |
| political | nato | NATO | 32 |
| political | commonwealth | Commonwealth of Nations | 56 |
| political | arab_league | Arab League | 22 |
| political | cis | CIS | 9 |
| economic | eurozone | Eurozone | 20 |
| economic | g7 | G7 | 7 |
| economic | g20 | G20 | 19 |
| economic | brics | BRICS+ | 9 |
| economic | opec | OPEC | 13 |
| economic | efta | EFTA | 4 |
| economic | mercosur | Mercosur | 5 |