MENU navbar-image

Introduction

Open data API for fuel prices, currency rates and vanlife events. Free to use with attribution (CC BY 4.0).

Welcome to the **OpenVan.camp Public API** — open data for fuel prices, currency rates and vanlife events. The fuel endpoint returns the current country count in `meta.total_countries`.

## License
All data is available under **[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)**.
You are free to use it in your apps, bots, and articles — please cite **OpenVan.camp (openvan.camp)** as the source.

## Base URL
All endpoints are available at `https://openvan.camp`.

## Authentication
No authentication required. All endpoints are public.

## Rate Limits
Public endpoints are limited to **120 requests/minute per IP** (some helper endpoints 30–60/min).
Watch the `X-RateLimit-Limit` / `X-RateLimit-Remaining` response headers; exceeding the limit returns **HTTP 429**.
Data is cached — please don't poll more often than every 10 minutes.

## Attribution
Every response includes an `_attribution` object with license and attribution details:

```json
"_attribution": {
  "data_source": "openvan.camp",
  "license": "CC BY 4.0",
  "attribution_url": "https://openvan.camp/",
  "attribution_html": "Data: <a href=\"https://openvan.camp/\">OpenVan.camp</a> (CC BY 4.0)"
}
```

Pass `?source=yoursite.com` to identify your integration — no registration required. Your value is echoed back as `_attribution.your_source`:

```
GET /api/fuel/prices?source=myapp.com
```

<aside>Code examples are shown in the right panel. Switch language with the tabs at the top right.</aside>

Authenticating requests

This API is not authenticated.

Currency Rates

Get currency rates

Returns EUR-base exchange rates. By default the response is limited to ~165 ISO 4217 active fiat currencies that are realistic for travel/fuel-price use cases.

Source chain: national central banks (RUB/TRY/GEL/UAH/BYN/UZS) for precision, then Fawaz API / ExchangeRate-API / Frankfurter / ECB for the long tail.

Refresh: Redis-backed cache stored forever; refreshed by cron every 6 hours. A separate hourly watchdog alerts in Telegram if cache > 25h old.

HTTP cache: Cache-Control: public, max-age=1800 (edge X-Accel-Expires: 1800). Edge кеш 30 минут — соответствует фактической частоте обновления (раз в 6 часов). Note: PHP-уровневый Cache-Control затирается nginx через fastcgi_hide_header + cache-control-map.conf, поэтому фактический header в ответе всегда задаётся nginx.

Query parameters:

Market overrides: the meta.overrides field lists codes whose rate is a manual market-rate override rather than an official feed. Currently only CUP (Cuba uses a parallel market rate of ~120 CUP/USD; the official fixing of ~24 CUP/USD does not reflect retail fuel pricing).

License: CC BY 4.0 — free to use with attribution to OpenVan.camp.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/currency/rates" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/currency/rates"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/currency/rates'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "success": true,
    "rates": {
        "EUR": 1,
        "USD": 1.1641,
        "GBP": 0.8729,
        "RUB": 84.0742,
        "TRY": 53.0915,
        "GEL": 3.1146
    },
    "meta": {
        "count": 165,
        "base": "EUR",
        "updated_at": "2026-05-19T12:24:28+00:00",
        "refreshed_every_hours": 6,
        "max_age_seconds": 90000,
        "scope": "fiat",
        "overrides": {
            "CUP": {
                "reason": "dual_exchange_rate",
                "source": "market_rate_120_cup_per_usd",
                "note": "Куба: официальный фиксинг ~24 CUP/USD расходится с реальным рынком ~120 CUP/USD."
            }
        }
    }
}
 

Request      

GET api/currency/rates

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Endpoints

POST api/route-cost

Example request:
curl --request POST \
    "https://openvan.camp/api/route-cost" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"waypoints\": [
        \"Волгоград\",
        \"Грузия\",
        \"Анталия\"
    ],
    \"tank\": 80,
    \"cons\": 10,
    \"fuel\": \"diesel\",
    \"currency\": \"RUB\",
    \"locale\": \"ru\"
}"
const url = new URL(
    "https://openvan.camp/api/route-cost"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "waypoints": [
        "Волгоград",
        "Грузия",
        "Анталия"
    ],
    "tank": 80,
    "cons": 10,
    "fuel": "diesel",
    "currency": "RUB",
    "locale": "ru"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/route-cost'
payload = {
    "waypoints": [
        "Волгоград",
        "Грузия",
        "Анталия"
    ],
    "tank": 80,
    "cons": 10,
    "fuel": "diesel",
    "currency": "RUB",
    "locale": "ru"
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Request      

POST api/route-cost

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

waypoints   string[]     

Названия 2–10 точек.

tank   number  optional    

Объём бака, л. Example: 80

cons   number  optional    

Расход, л/100 км. Example: 10

fuel   string  optional    

diesel|gasoline|lpg. Example: diesel

currency   string  optional    

ISO 4217. Example: RUB

locale   string  optional    

Язык названий стран. Example: ru

VanSky weather for all countries

Все страны — сводные данные для таблицы / карты. Ответ ~900 КБ, кешируется на 1 час.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/vansky/weather" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/vansky/weather"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/vansky/weather'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success (truncated)):


{
    "data": [
        {
            "country_code": "DE",
            "country_slug": "germany",
            "van_score": 90,
            "temp_day": 24.1,
            "temp_night": 14.3,
            "solar_kwh": 2.8,
            "sea_temp": 18.2,
            "is_coastal": true,
            "label": "ideal"
        }
    ],
    "count": 155,
    "updated_at": "2026-07-15T02:00:00+03:00",
    "source": "Open-Meteo (api.open-meteo.com)"
}
 

Request      

GET api/vansky/weather

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

VanSky weather for one country

Подробные данные одной страны (ISO 3166-1 alpha-2).

Example request:
curl --request GET \
    --get "https://openvan.camp/api/vansky/weather/DE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/vansky/weather/DE"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/vansky/weather/DE'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):

Show headers
cache-control: max-age=3600, public
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 114
x-seo: Liked our optimization? We do technical SEO + GEO. Let's talk -> https://openvan.camp/en/about#contacts
access-control-allow-origin: *
 

{
    "data": {
        "code": "DE",
        "marine": {
            "sea_temp": 19.5,
            "wave_dir": 295,
            "swell_dir": 247,
            "wave_height": 1.54,
            "wave_period": 4.6,
            "swell_height": 0,
            "swell_period": 5.8,
            "wind_wave_dir": 295,
            "wind_wave_height": 1.54,
            "wind_wave_period": 4.6
        },
        "region": "europe",
        "weather": {
            "sunset": "2026-07-26T18:58",
            "uv_max": null,
            "sunrise": "2026-07-26T03:41",
            "humidity": 65,
            "temp_day": 26.5,
            "wind_dir": 240,
            "wind_max": 15.7,
            "dew_point": 12.6,
            "precip_sum": 0.2,
            "temp_night": 18.4,
            "cloud_cover": 75,
            "temp_current": 19.4,
            "weather_code": 51,
            "feels_like_day": 25.3,
            "peak_sun_hours": 4.7,
            "sunshine_hours": 11.4,
            "wind_gusts_max": 37.4,
            "precip_prob_max": 0,
            "feels_like_night": 18,
            "feels_like_current": 18.9,
            "shortwave_radiation_sum": 16.89
        },
        "forecast": [
            {
                "date": "2026-07-26",
                "temp_day": 26.5,
                "solar_kwh": 2.1,
                "van_score": 97,
                "temp_night": 18.4,
                "drive_score": 100,
                "score_label": "ideal",
                "sleep_score": 97,
                "weather_code": 51
            },
            {
                "date": "2026-07-27",
                "temp_day": 25.5,
                "solar_kwh": 2.1,
                "van_score": 94,
                "temp_night": 16.8,
                "drive_score": 99,
                "score_label": "ideal",
                "sleep_score": 95,
                "weather_code": 2
            },
            {
                "date": "2026-07-28",
                "temp_day": 28.4,
                "solar_kwh": 2.8,
                "van_score": 73,
                "temp_night": 14,
                "drive_score": 100,
                "score_label": "comfortable",
                "sleep_score": 88,
                "weather_code": 0
            },
            {
                "date": "2026-07-29",
                "temp_day": 33.1,
                "solar_kwh": 2.8,
                "van_score": 53,
                "temp_night": 16.8,
                "drive_score": 100,
                "score_label": "acceptable",
                "sleep_score": 89,
                "weather_code": 51
            },
            {
                "date": "2026-07-30",
                "temp_day": 36.2,
                "solar_kwh": 2.7,
                "van_score": 82,
                "temp_night": 19.7,
                "drive_score": 94,
                "score_label": "ideal",
                "sleep_score": 95,
                "weather_code": 1
            },
            {
                "date": "2026-07-31",
                "temp_day": 33.7,
                "solar_kwh": 2.2,
                "van_score": 95,
                "temp_night": 20.7,
                "drive_score": 100,
                "score_label": "ideal",
                "sleep_score": 93,
                "weather_code": 51
            },
            {
                "date": "2026-08-01",
                "temp_day": 28.8,
                "solar_kwh": 2.3,
                "van_score": 90,
                "temp_night": 19,
                "drive_score": 98,
                "score_label": "ideal",
                "sleep_score": 84,
                "weather_code": 61
            }
        ],
        "sea_score": null,
        "solar_kwh": 2.1,
        "van_score": 97,
        "confidence": "high",
        "fetched_at": "2026-07-26T23:22:45.181608Z",
        "is_coastal": true,
        "week_score": 69,
        "band_counts": {
            "hard": 0,
            "ideal": 33,
            "extreme": 0,
            "acceptable": 473,
            "comfortable": 1269
        },
        "drive_score": 100,
        "score_label": "ideal",
        "sleep_score": 96,
        "solar_score": 46,
        "drive_window": null,
        "awning_status": "caution",
        "best_move_day": {
            "date": "2026-07-26",
            "temp_day": 26.5,
            "solar_kwh": 2.1,
            "van_score": 93,
            "temp_night": 18.4,
            "drive_score": 100,
            "score_label": "ideal",
            "sleep_score": 97,
            "weather_code": 51
        },
        "sample_points": 1775,
        "typical_score": 65,
        "ideal_coverage": 0,
        "sample_regions": 16,
        "best_area_score": 72,
        "recommendations": [
            {
                "key": "vansky.rec.awning_caution",
                "type": "warning",
                "params": {
                    "gusts": 37.4
                }
            },
            {
                "key": "vansky.rec.night_ideal",
                "type": "success",
                "params": {
                    "temp": 19.1
                }
            },
            {
                "key": "vansky.rec.day_comfortable",
                "type": "success",
                "params": {
                    "temp": 24.7
                }
            }
        ],
        "condensation_risk": "low",
        "aggregation_version": 2,
        "comfortable_coverage": 81
    },
    "updated_at": "2026-07-27T02:23:24+03:00",
    "source": "Open-Meteo (api.open-meteo.com)"
}
 

Example response (404, Not found):


{
    "error": "Country not found or not supported"
}
 

Request      

GET api/vansky/weather/{code}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

ISO 3166-1 alpha-2 код страны. Example: DE

Events

List events

Returns a paginated list of vanlife events (exhibitions, festivals, meetups, road trips). Filter by status, type, country, or search by name.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/events?locale=en&status=upcoming&type=festival&country=DE&search=Adventure+Northside&page=1&limit=30" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/events"
);

const params = {
    "locale": "en",
    "status": "upcoming",
    "type": "festival",
    "country": "DE",
    "search": "Adventure Northside",
    "page": "1",
    "limit": "30",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/events'
params = {
  'locale': 'en',
  'status': 'upcoming',
  'type': 'festival',
  'country': 'DE',
  'search': 'Adventure Northside',
  'page': '1',
  'limit': '30',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "events": [
        {
            "id": 960,
            "slug": "adventure-northside-2026",
            "event_name": "Adventure Northside 2026",
            "event_type": "festival",
            "event_type_emoji": "🎉",
            "start_date": "2026-09-18",
            "end_date": "2026-09-20",
            "city": "Basthorst",
            "country_code": "DE",
            "country": {
                "code": "de",
                "slug": "germany",
                "name": "Germany",
                "flag_emoji": "🇩🇪"
            },
            "status": "upcoming",
            "url": "https://openvan.camp/en/event/adventure-northside-2026"
        }
    ],
    "pagination": {
        "total": 48,
        "page": 1,
        "limit": 30,
        "pages": 2
    }
}
 

Request      

GET api/events

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

locale   string  optional    

Language code for localized names. One of: en, ru, de, fr, es, pt, tr. Defaults to en. Example: en

status   string  optional    

Filter by event status. One of: upcoming, ongoing, past, all. Defaults to upcoming. Example: upcoming

type   string  optional    

Filter by event type. One of: expo, festival, forum, meetup, roadtrip. Example: festival

country   string  optional    

2-letter ISO country code. Example: DE

search   string  optional    

Text search by event name. Example: Adventure Northside

page   integer  optional    

Page number. Defaults to 1. Example: 1

limit   integer  optional    

Results per page (max 100). Defaults to 30. Example: 30

Get event details

Returns full details for a single vanlife event by slug, including location, description, and social links.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/event/adventure-northside-2026?locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/event/adventure-northside-2026"
);

const params = {
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/event/adventure-northside-2026'
params = {
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "id": 960,
    "slug": "adventure-northside-2026",
    "event_name": "Adventure Northside 2026",
    "event_type": "festival",
    "event_type_emoji": "🎉",
    "start_date": "2026-09-18",
    "end_date": "2026-09-20",
    "city": "Basthorst",
    "country_code": "DE",
    "description": "Northern Germany's Overland & Self-build expo and festival...",
    "official_url": "https://adventurenorthside.de/",
    "image_url": "https://...",
    "status": "upcoming",
    "url": "https://openvan.camp/en/event/adventure-northside-2026"
}
 

Example response (404, Not found):


{
    "message": "No query results for model [App\\Models\\Event]."
}
 

Request      

GET api/event/{slug}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The event slug. Example: adventure-northside-2026

Query Parameters

locale   string  optional    

Language for localized content. One of: en, ru, de, fr, es, pt, tr. Example: en

Get event articles

Returns source articles linked to this event. When locale is provided, attempts to return only articles in that language. If no articles match the requested locale, all articles are returned as a fallback (they may be in the original source language, e.g. Japanese or German). The language field on each article indicates the actual language of the source.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/event/adventure-northside-2026/articles?locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/event/adventure-northside-2026/articles"
);

const params = {
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/event/adventure-northside-2026/articles'
params = {
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


[
    {
        "id": 1001,
        "title": "Adventure Northside 2026 opens its doors",
        "image_url": "https://...",
        "published_at": "2026-03-11T10:00:00+00:00",
        "source_name": "CamperVan Magazine",
        "original_url": "https://...",
        "language": "en"
    }
]
 

Request      

GET api/event/{slug}/articles

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The event slug. Example: adventure-northside-2026

Query Parameters

locale   string  optional    

Language code to filter articles by source language. One of: en, ru, de, fr, es, pt, tr. Defaults to en. Example: en

Fuel Prices

Get fuel prices

Returns current retail fuel prices for all supported countries. Price keys follow FuelGradeCatalog::ORDER plus the legacy premium alias. Data is updated weekly from 45+ official government sources and independent aggregators.

Prices are weighted averages from multiple sources per country. The sources array lists all contributing data providers (sorted by trust weight, highest first).

License: CC BY 4.0 — free to use with attribution to OpenVan.camp.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/fuel/prices" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/fuel/prices"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/fuel/prices'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "success": true,
    "data": {
        "DE": {
            "country_code": "DE",
            "country_name": "Germany",
            "region": "europe",
            "currency": "EUR",
            "local_currency": "EUR",
            "unit": "liter",
            "prices": {
                "gasoline_regular": null,
                "gasoline": 2.1313,
                "gasoline_premium": null,
                "gasoline_super": null,
                "diesel_regular": null,
                "diesel": 2.2845,
                "diesel_premium": null,
                "lpg": 1.113,
                "cng": null,
                "e85": null,
                "kerosene": null,
                "premium": null
            },
            "price_changes": {
                "gasoline_regular": null,
                "gasoline": -0.02,
                "gasoline_premium": null,
                "gasoline_super": null,
                "diesel_regular": null,
                "diesel": 0.01,
                "diesel_premium": null,
                "lpg": 0,
                "cng": null,
                "e85": null,
                "kerosene": null,
                "premium": null
            },
            "fetched_at": "2026-06-29T11:12:55+00:00",
            "sources": [
                "Fuelo.net",
                "EU Weekly Oil Bulletin",
                "Cargopedia.net"
            ],
            "sources_count": 3,
            "is_excluded": false
        }
    },
    "meta": {
        "total_countries": 135,
        "updated_at": "2026-06-29 11:12:55",
        "cache_ttl_hours": 6
    }
}
 

Request      

GET api/fuel/prices

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Stories

Vanlife news stories — clustered and translated into 7 languages. Each story aggregates multiple source articles from different publishers.

List stories

Returns a paginated list of vanlife news stories in the requested language. Titles and summaries are translated; sources are original-language articles.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/stories?locale=en&category=festival&country=DE&search=vanlife+festival&page=1&limit=20" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/stories"
);

const params = {
    "locale": "en",
    "category": "festival",
    "country": "DE",
    "search": "vanlife festival",
    "page": "1",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/stories'
params = {
  'locale': 'en',
  'category': 'festival',
  'country': 'DE',
  'search': 'vanlife festival',
  'page': '1',
  'limit': '20',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "stories": [
        {
            "slug": "adac-camper-des-jahres-der-wettbewerb-fuer",
            "title": "ADAC launches 'Camper of the Year' competition for motorhome drivers",
            "summary": "ADAC is holding the national 'Camper des Jahres 2026' competition for motorhome owners...",
            "image_url": "https://...",
            "category": {
                "slug": "festival",
                "name": "Festivals"
            },
            "countries": [
                {
                    "code": "de",
                    "name": "Germany",
                    "flag_emoji": "🇩🇪"
                }
            ],
            "first_published_at": "2026-01-22T11:00:00+03:00",
            "articles_count": 5,
            "url": "https://openvan.camp/en/news/festival/adac-camper-des-jahres-der-wettbewerb-fuer"
        }
    ],
    "pagination": {
        "total": 120,
        "page": 1,
        "limit": 20,
        "pages": 6
    }
}
 

Request      

GET api/stories

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

locale   string  optional    

Language for localized titles and summaries. One of: en, ru, de, fr, es, pt, tr. Defaults to en. Example: en

category   string  optional    

Filter by category slug. One of: lifestyle, industry, incident, opening, closing, law, builds, festival, expo, review, ban, other. Example: festival

country   string  optional    

2-letter ISO country code to filter by associated country. Example: DE

search   string  optional    

Full-text search by story title. Example: vanlife festival

page   integer  optional    

Page number. Defaults to 1. Example: 1

limit   integer  optional    

Results per page (max 50). Defaults to 20. Example: 20

Get story details

Returns full details for a single news story including all source articles. The sources array contains original publisher articles with direct links.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/story/adac-camper-des-jahres-der-wettbewerb-fuer?locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/story/adac-camper-des-jahres-der-wettbewerb-fuer"
);

const params = {
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/story/adac-camper-des-jahres-der-wettbewerb-fuer'
params = {
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "slug": "adac-camper-des-jahres-der-wettbewerb-fuer",
    "title": "ADAC launches 'Camper of the Year' competition for motorhome drivers",
    "summary": "ADAC is holding the national 'Camper des Jahres 2026' competition for motorhome owners...",
    "image_url": "https://...",
    "category": {
        "slug": "festival",
        "name": "Festivals"
    },
    "countries": [
        {
            "code": "de",
            "name": "Germany",
            "flag_emoji": "🇩🇪"
        }
    ],
    "first_published_at": "2026-01-22T11:00:00+03:00",
    "last_updated_at": "2026-07-04T04:16:47+03:00",
    "articles_count": 5,
    "url": "https://openvan.camp/en/news/festival/adac-camper-des-jahres-der-wettbewerb-fuer",
    "sources": [
        {
            "title": "Nürburgring: Bundesweiter Wettbewerb «Camper des Jahres»",
            "original_url": "https://www.blick-aktuell.de/Berichte/...",
            "source_name": "BLICK aktuell",
            "published_at": "2026-04-30T09:24:20+03:00",
            "language": "de",
            "image_url": "https://..."
        }
    ]
}
 

Example response (404, Not found):


{
    "error": "Story not found."
}
 

Request      

GET api/story/{slug}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The story slug. Example: adac-camper-des-jahres-der-wettbewerb-fuer

Query Parameters

locale   string  optional    

Language for localized title and summary. One of: en, ru, de, fr, es, pt, tr. Defaults to en. Example: en

Semantic search over news via the same engine as the /{locale}/search page (SemanticSearchService: Jina embeddings + pgvector). Returns matching news stories ranked by similarity. Story summary shape matches /stories.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/news/search?q=ford+camper+2026&locale=ru&limit=8" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/news/search"
);

const params = {
    "q": "ford camper 2026",
    "locale": "ru",
    "limit": "8",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/news/search'
params = {
  'q': 'ford camper 2026',
  'locale': 'ru',
  'limit': '8',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 115
x-seo: Liked our optimization? We do technical SEO + GEO. Let's talk -> https://openvan.camp/en/about#contacts
access-control-allow-origin: *
 

{
    "results": [
        {
            "slug": "panoramic-ford-f-camper-truck-costs-fraction",
            "title": "Supertramp представила кемпер Paragon на базе Ford F-350",
            "summary": "Компания Supertramp анонсировала новую модель кемпера Paragon на шасси Ford F-350. Базовая цена составляет 199 000 долларов, что значительно ниже конкурентов, таких как Earthroamer (от 825 000 долларов) и Winnebago Arka (330 000 долларов). Модель оснащена композитным модулем с вакуумной инфузией, спальными местами на четыре человека и опциональной палаткой на крыше для шести человек. Стандартная комплектация включает литий-ионную батарею на 270 А·ч, инвертор на 3000 Вт и солнечную систему на 660 Вт.",
            "image_url": "https://assets.newatlas.com/dims4/default/00d5475/2147483647/strip/true/crop/3276x1720+0+514/resize/1200x630!/quality/85/?url=https%3A%2F%2Fnewatlas-brightspot.s3.amazonaws.com%2Fb8%2F31%2F5eb910d0450196ac9000fdc083c3%2F699761506-18360938500231222-6098785867930289037-n.jpg&na.image_optimisation=0",
            "category": {
                "slug": "industry",
                "name": "Индустрия"
            },
            "countries": [],
            "first_published_at": "2026-06-05T04:35:09+03:00",
            "articles_count": 1,
            "url": "https://openvan.camp/ru/news/industry/panoramic-ford-f-camper-truck-costs-fraction",
            "score": 0.562
        },
        {
            "slug": "ram-promaster-add-new-prebuilt-camper-van-thats",
            "title": "Ram ProMaster 2027 получил пакет Vanlife для автодомов",
            "summary": "Компания Ram представила пакет Vanlife для фургона ProMaster 2027 года, упрощающий переоборудование в кемпер. Цена — от $60 320.",
            "image_url": "https://hips.hearstapps.com/hmg-prod/images/94800d47-567d-49f8-8bb7-2996f6c8af4c.jpg?crop=1.00xw:0.753xh;0,0.171xh&amp;resize=1200:*",
            "category": {
                "slug": "industry",
                "name": "Индустрия"
            },
            "countries": [
                {
                    "code": "ru",
                    "name": "Россия",
                    "flag_emoji": "🇷🇺"
                },
                {
                    "code": "us",
                    "name": "США",
                    "flag_emoji": "🇺🇸"
                }
            ],
            "first_published_at": "2026-06-02T20:53:00+03:00",
            "articles_count": 6,
            "url": "https://openvan.camp/ru/news/industry/ram-promaster-add-new-prebuilt-camper-van-thats",
            "score": 0.533
        },
        {
            "slug": "ford-convierte-la-transit-custom-en-la-mejor",
            "title": "Carado T457 на базе Ford Transit признан лучшим автодомом 2026 года по версии Red Dot Awards",
            "summary": "Модель Carado T457, полуинтегрированный автодом на платформе Ford Transit, получил награду Red Dot Design Awards 2026. Длина — 7,4 м, ширина — 2,32 м, высота — 2,93 м. Цена от 71 690 евро.",
            "image_url": "https://album.mediaset.es/eimg/2026/01/03/ford-logo-16-9-aspect-ratio-default-1027707_da39.jpg",
            "category": {
                "slug": "industry",
                "name": "Индустрия"
            },
            "countries": [
                {
                    "code": "de",
                    "name": "Германия",
                    "flag_emoji": "🇩🇪"
                }
            ],
            "first_published_at": "2026-02-18T10:20:01+03:00",
            "articles_count": 2,
            "url": "https://openvan.camp/ru/news/industry/ford-convierte-la-transit-custom-en-la-mejor",
            "score": 0.529
        },
        {
            "slug": "dfsk-tebar-promo-besar-di-prj-2026-mulai",
            "title": "DFSK на PRJ 2026: кемпер Delima x Explora и анонс PHEV",
            "summary": "На Jakarta Fair Kemayoran 2026 компания DFSK представила Camper Van Delima x Explora, электромобили и анонсировала технологию Plug-in Hybrid Electric Vehicle (PHEV). Действуют программы trade-in и бесплатного обслуживания.",
            "image_url": "https://dapurletter.id/wp-content/uploads/2026/06/PRJ-DFSK-2.jpeg",
            "category": {
                "slug": "expo",
                "name": "Выставки"
            },
            "countries": [
                {
                    "code": "id",
                    "name": "Индонезия",
                    "flag_emoji": "🇮🇩"
                }
            ],
            "first_published_at": "2026-06-11T07:13:45+03:00",
            "articles_count": 2,
            "url": "https://openvan.camp/ru/news/expo/dfsk-tebar-promo-besar-di-prj-2026-mulai",
            "score": 0.524
        },
        {
            "slug": "chrysler-pacifica-awd-minit-campervan-brings-van",
            "title": "2026 Chrysler Pacifica AWD Mini-T Campervan",
            "summary": "Компания DLM-Distribution представила кемпер на базе Chrysler Pacifica с полным приводом. Модель помещается в стандартный гараж и оснащена спальным местом, холодильником, раковиной и солнечной батареей. Цена — $66 900.",
            "image_url": "https://moparinsiders.com/wp-content/uploads/2026/05/2026-Chrysler-Pacifica-AWD-Mini-T-Campervan.-DLM-Distribution.-1.jpeg",
            "category": {
                "slug": "industry",
                "name": "Индустрия"
            },
            "countries": [
                {
                    "code": "us",
                    "name": "США",
                    "flag_emoji": "🇺🇸"
                }
            ],
            "first_published_at": "2026-05-17T19:00:21+03:00",
            "articles_count": 1,
            "url": "https://openvan.camp/ru/news/industry/chrysler-pacifica-awd-minit-campervan-brings-van",
            "score": 0.524
        },
        {
            "slug": "volkswagen-id-buzz-coming-back-america-van-camp",
            "title": "Volkswagen возвращает кемпер ID. Buzz в США с новой комплектацией Tourer",
            "summary": "Volkswagen представил комплектацию Tourer для электрического микроавтобуса ID. Buzz 2027 года, предназначенную для кемпинга. В оснащение входят складная кровать, шторки, режим Overnight и уличная мебель. Продажи начнутся в 2027 году, цены пока не объявлены.",
            "image_url": "https://images-stag.jazelc.com/uploads/theautopian-m2en/ID_Camper_TS2.png",
            "category": {
                "slug": "industry",
                "name": "Индустрия"
            },
            "countries": [
                {
                    "code": "us",
                    "name": "США",
                    "flag_emoji": "🇺🇸"
                }
            ],
            "first_published_at": "2026-05-14T16:49:00+03:00",
            "articles_count": 7,
            "url": "https://openvan.camp/ru/news/industry/volkswagen-id-buzz-coming-back-america-van-camp",
            "score": 0.523
        }
    ],
    "timing_ms": 60,
    "_attribution": {
        "data_source": "openvan.camp",
        "license": "CC BY 4.0",
        "attribution_url": "https://openvan.camp/",
        "attribution_html": "Data: <a href=\"https://openvan.camp/\">OpenVan.camp</a> (CC BY 4.0)"
    }
}
 

Daily news digest (raw content)

Returns the structured evening news digest for the requested locale, assembled once per evening by the site. Consumers (site social channels,

Example request:
curl --request GET \
    --get "https://openvan.camp/api/news/digest?locale=ru" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/news/digest"
);

const params = {
    "locale": "ru",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/news/digest'
params = {
  'locale': 'ru',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "locale": "ru",
    "date": "2026-07-25",
    "intro": "Дороги сегодня подкинули всё…",
    "groups": [
        {
            "key": "incident",
            "title": "⚠️ Происшествия",
            "items": [
                {
                    "id": 123,
                    "flag": "🇩🇪",
                    "hook": "Заголовок-зацепка",
                    "detail": "Деталь сюжета",
                    "url": "https://openvan.camp/ru/news/incident/slug"
                }
            ]
        }
    ]
}
 

Example response (204, No digest yet):

Empty response
 

Request      

GET api/news/digest

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

locale   string  optional    

Digest language. Currently ru or en. Defaults to ru. Example: ru

VanBasket Food Price Index

VanBasket Index shows how expensive food is in a country relative to the world average (World = 100). Based on World Bank ICP 2021 data, adjusted with IMF CPI.

Get all countries with VanBasket index.

Returns food price index for 90+ countries. World average = 100. Above 100 = more expensive, below 100 = cheaper.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/vanbasket/countries" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/vanbasket/countries"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/vanbasket/countries'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "success": true,
    "data": {
        "DE": {
            "country_code": "DE",
            "country_name": "Germany",
            "vanbasket_index": 124.9,
            "pct_vs_world": 24.9
        }
    },
    "meta": {
        "total_countries": 92
    }
}
 

Request      

GET api/vanbasket/countries

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Compare food prices between two countries.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/vanbasket/compare?from=DE&to=TR" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/vanbasket/compare"
);

const params = {
    "from": "DE",
    "to": "TR",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/vanbasket/compare'
params = {
  'from': 'DE',
  'to': 'TR',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": {
        "from": {
            "country_code": "DE",
            "country_name": "Germany",
            "vanbasket_index": 124.9
        },
        "to": {
            "country_code": "TR",
            "country_name": "Turkey",
            "vanbasket_index": 88
        },
        "diff_percent": -29.5,
        "budget_100": 70,
        "cheaper": true
    }
}
 

Request      

GET api/vanbasket/compare

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

from   string     

ISO 3166-1 alpha-2 code of home country. Example: DE

to   string     

ISO 3166-1 alpha-2 code of destination country. Example: TR

Get VanBasket country details

Detailed data for a single country including historical snapshots.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/vanbasket/countries/DE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/vanbasket/countries/DE"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/vanbasket/countries/DE'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "success": true,
    "data": {
        "country": {
            "country_code": "DE",
            "vanbasket_index": 124.9
        },
        "snapshots": [
            {
                "snapshot_date": "2021-01-01",
                "vanbasket_index": 124.9
            }
        ]
    }
}
 

Request      

GET api/vanbasket/countries/{code}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

ISO 3166-1 alpha-2 country code. Example: DE

Visa & Border Rules

How long you may stay and how the days are counted — for all 199 × 199 passport/destination pairs, plus temporary vehicle import rules.

Every answer carries confidence and source_url, and says which layer it came from: curated (hand-verified), window (counting window applied on top of the dataset), zone (Schengen-style shared counter) or dataset. Treat confidence: low as "the number of days is right, the way they are counted is an assumption" — verify at the border.

Check a passport against a destination.

Returns the stay rule (days, counting window, whether a visa run resets the counter), the entry mode, and the vehicle import rule for the same destination.

If the country belongs to a shared-counter zone, the stay rule is the zone's — entering Spain spends Schengen days, not "Spanish" ones — and counted_against names the place the counter belongs to.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/check?passport=RU&destination=TR&weight=le35&plate=third&locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/check"
);

const params = {
    "passport": "RU",
    "destination": "TR",
    "weight": "le35",
    "plate": "third",
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/check'
params = {
  'passport': 'RU',
  'destination': 'TR',
  'weight': 'le35',
  'plate': 'third',
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": {
        "passport": {
            "code": "RU",
            "name": "Russia"
        },
        "destination": {
            "code": "TR",
            "name": "Turkey",
            "kind": "country",
            "zone": null
        },
        "entry_mode": "visa_free",
        "stay": {
            "visa_type": "visa_free",
            "max_continuous": 90,
            "max_total": 90,
            "window": "rolling",
            "window_days": 180,
            "visa_run": false,
            "confidence": "high",
            "source_url": "https://www.mfa.gov.tr/visa-information-for-foreigners.en.mfa",
            "note": "Безвиз 90/180.",
            "layer": "curated"
        },
        "vehicle": {
            "max_days": null,
            "basis": "tied_to_person",
            "green_card": "required",
            "confidence": "high"
        }
    }
}
 

Example response (422):


{
    "success": false,
    "error": "Parameters \"passport\" and \"destination\" are required."
}
 

Request      

GET api/visa/check

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

passport   string     

ISO 3166-1 alpha-2 code of the passport. Example: RU

destination   string     

ISO alpha-2 code, slug or zone code. Example: TR

weight   string  optional    

Vehicle weight class for the vehicle rule: le35 (≤3.5t) or gt35. Example: le35

plate   string  optional    

Vehicle plate origin for the vehicle rule: eu, non_eu, eaeu, third. Example: third

locale   string  optional    

Language of place names, one of ru/en/de/es/fr/pt/tr. Defaults to en. Example: en

Passport ranking by destinations reachable without a prior visa.

Score = visa free + visa on arrival + eTA. The breakdown is returned alongside so the number can be checked rather than taken on faith. Ties share a rank.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/rank?limit=10&locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/rank"
);

const params = {
    "limit": "10",
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/rank'
params = {
  'limit': '10',
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": [
        {
            "rank": 1,
            "passport": "SG",
            "name": "Singapore",
            "score": 168,
            "visa_free": 130,
            "visa_on_arrival": 30,
            "eta": 8,
            "e_visa": 20,
            "visa_required": 10
        }
    ],
    "meta": {
        "total": 199,
        "scoring": "visa_free + visa_on_arrival + eta"
    }
}
 

Request      

GET api/visa/rank

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

limit   integer  optional    

How many rows to return, 1..199. Defaults to all. Example: 10

locale   string  optional    

Language of passport names. Defaults to en. Example: en

Change log of visa and vehicle rules.

One row per changed field, written both by imports and by editors. Commercial passport APIs charge for rule history; this one is open.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/history?subject_type=requirement&subject_key=RU%3ETR&since=2026-01-01&limit=50" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/history"
);

const params = {
    "subject_type": "requirement",
    "subject_key": "RU>TR",
    "since": "2026-01-01",
    "limit": "50",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/history'
params = {
  'subject_type': 'requirement',
  'subject_key': 'RU>TR',
  'since': '2026-01-01',
  'limit': '50',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": [
        {
            "subject_type": "requirement",
            "subject_key": "RU>TR",
            "field": "days",
            "old_value": "60",
            "new_value": "90",
            "source": "import",
            "changed_at": "2026-07-27T10:00:00+00:00"
        }
    ],
    "meta": {
        "total": 1
    }
}
 

Request      

GET api/visa/history

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

subject_type   string  optional    

Filter: requirement, window, window_exception, curated_rule, vehicle_rule, place. Example: requirement

subject_key   string  optional    

Filter by subject, e.g. RU>TR for a pair or TR for a place. Example: RU>TR

since   string  optional    

ISO date, only changes on or after it. Example: 2026-01-01

limit   integer  optional    

1..500, defaults to 100. Example: 50

All destinations for one passport.

199 rows resolved through the full chain, sorted by destination name. Counts by entry mode are in meta.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/passport/DE?mode=visa_free&locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/passport/DE"
);

const params = {
    "mode": "visa_free",
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/passport/DE'
params = {
  'mode': 'visa_free',
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": [
        {
            "destination": "TR",
            "name": "Turkey",
            "slug": "turkey",
            "mode": "visa_free",
            "days": 90,
            "stay": {
                "window": "rolling",
                "window_days": 180,
                "confidence": "medium",
                "layer": "window"
            }
        }
    ],
    "meta": {
        "passport": "DE",
        "total": 199,
        "by_mode": {
            "visa_free": 130
        }
    }
}
 

Request      

GET api/visa/passport/{code}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

ISO 3166-1 alpha-2 code of the passport. Example: DE

Query Parameters

mode   string  optional    

Filter by entry mode: visa_free, visa_required, e_visa, eta, voa, no_admission. Example: visa_free

locale   string  optional    

Language of place names. Defaults to en. Example: en

Compact payload for colouring a world map by one passport.

Same data as /passport/{code} stripped to what a choropleth needs: m — entry mode, d — visa-free days if known.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/map/US" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/map/US"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/map/US'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "success": true,
    "data": {
        "TR": {
            "m": "visa_free",
            "d": 90
        },
        "RU": {
            "m": "visa_required",
            "d": null
        }
    },
    "meta": {
        "passport": "US",
        "legend": [
            "visa_free",
            "voa",
            "eta",
            "e_visa",
            "visa_required",
            "no_admission",
            "self"
        ]
    }
}
 

Request      

GET api/visa/map/{code}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

ISO 3166-1 alpha-2 code of the passport. Example: US

Temporary vehicle import rules for a country.

Only rules we can stand behind are returned: an official source, or two independent research runs agreeing, or manual verification. A country with nothing trustworthy returns an empty list rather than a guess — the cost of being wrong here is a vehicle held at the border.

Example request:
curl --request GET \
    --get "https://openvan.camp/api/visa/vehicle/georgia?locale=en" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://openvan.camp/api/visa/vehicle/georgia"
);

const params = {
    "locale": "en",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://openvan.camp/api/visa/vehicle/georgia'
params = {
  'locale': 'en',
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "success": true,
    "data": [
        {
            "weight_class": "le35",
            "plate_group": null,
            "max_days": 90,
            "basis": "per_entry",
            "window_days": null,
            "carnet_required": false,
            "extension_possible": null,
            "green_card": "border_insurance",
            "confidence": "high",
            "source_url": "https://georgiacb.com/en/articles/customs-procedure-temporary-importation-admission-im-53",
            "curated": true
        }
    ],
    "meta": {
        "place": "GE",
        "name": "Georgia",
        "green_card_by_plate": {
            "eu": "plate_ok"
        }
    }
}
 

Request      

GET api/visa/vehicle/{place}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

place   string     

ISO alpha-2 code, slug or zone code. Example: georgia

Query Parameters

locale   string  optional    

Language of the place name. Defaults to en. Example: en