openapi: 3.0.3 info: title: 'OpenVan.camp — Public API' description: 'Open data API for fuel prices, currency rates and vanlife events. Free to use with attribution (CC BY 4.0).' version: 1.0.0 servers: - url: 'https://openvan.camp' tags: - name: 'Currency Rates' description: '' - name: Endpoints description: '' - name: Events description: '' - name: 'Fuel Prices' description: '' - name: Stories description: "\nVanlife news stories — clustered and translated into 7 languages.\nEach story aggregates multiple source articles from different publishers." - name: 'VanBasket Food Price Index' description: "\nVanBasket Index shows how expensive food is in a country\nrelative to the world average (World = 100).\nBased on World Bank ICP 2021 data, adjusted with IMF CPI." - name: 'Visa & Border Rules' description: "\nHow long you may stay and how the days are counted — for all 199 × 199\npassport/destination pairs, plus temporary vehicle import rules.\n\nEvery answer carries `confidence` and `source_url`, and says which layer it\ncame from: `curated` (hand-verified), `window` (counting window applied on\ntop of the dataset), `zone` (Schengen-style shared counter) or `dataset`.\nTreat `confidence: low` as \"the number of days is right, the way they are\ncounted is an assumption\" — verify at the border." paths: /api/currency/rates: get: summary: 'Get currency rates' operationId: getCurrencyRates description: "Returns EUR-base exchange rates. By default the response is limited to ~165 ISO 4217\nactive fiat currencies that are realistic for travel/fuel-price use cases.\n\n**Source chain:** national central banks (RUB/TRY/GEL/UAH/BYN/UZS) for precision,\nthen Fawaz API / ExchangeRate-API / Frankfurter / ECB for the long tail.\n\n**Refresh:** Redis-backed cache stored `forever`; refreshed by cron every 6 hours.\nA separate hourly watchdog alerts in Telegram if cache > 25h old.\n\n**HTTP cache:** `Cache-Control: public, max-age=1800` (edge `X-Accel-Expires: 1800`).\nEdge кеш 30 минут — соответствует фактической частоте обновления (раз в 6 часов).\nNote: PHP-уровневый Cache-Control затирается nginx через `fastcgi_hide_header` +\n`cache-control-map.conf`, поэтому фактический header в ответе всегда задаётся nginx.\n\n**Query parameters:**\n- `include=all` — return the raw upstream set (~340 codes), including crypto, metals\n and historical/legacy codes (BTC, ETH, USDT, XAU, ATS, DEM, VEF, TRL, ZWL, etc.).\n Without this parameter, those are filtered out.\n\n**Market overrides:** the `meta.overrides` field lists codes whose rate is a manual\nmarket-rate override rather than an official feed. Currently only **CUP** (Cuba uses\na parallel market rate of ~120 CUP/USD; the official fixing of ~24 CUP/USD does not\nreflect retail fuel pricing).\n\n**License:** CC BY 4.0 — free to use with attribution to [OpenVan.camp](https://openvan.camp)." parameters: [] responses: 200: description: Success content: application/json: schema: type: object example: success: true rates: EUR: 1 USD: 1.16698 GBP: 0.855238 RUB: 98.2897 TRY: 56.1398 GEL: 3.0551 meta: count: 152 base: EUR updated_at: '2026-08-27T03:05:15+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.' properties: success: type: boolean example: true rates: type: object properties: EUR: type: integer example: 1 USD: type: number example: 1.16698 GBP: type: number example: 0.855238 RUB: type: number example: 98.2897 TRY: type: number example: 56.1398 GEL: type: number example: 3.0551 meta: type: object properties: count: type: integer example: 152 base: type: string example: EUR updated_at: type: string example: '2026-08-27T03:05:15+00:00' refreshed_every_hours: type: integer example: 6 max_age_seconds: type: integer example: 90000 scope: type: string example: fiat overrides: type: object properties: CUP: type: object properties: reason: type: string example: dual_exchange_rate source: type: string example: market_rate_120_cup_per_usd note: type: string example: 'Куба: официальный фиксинг ~24 CUP/USD расходится с реальным рынком ~120 CUP/USD.' tags: - 'Currency Rates' security: [] /api/route-cost: post: summary: '' operationId: postApiRouteCost description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: waypoints: type: array description: 'Названия 2–10 точек.' example: - Волгоград - Грузия - Анталия items: type: string tank: type: number description: 'Объём бака, л.' example: 80.0 nullable: true cons: type: number description: 'Расход, л/100 км.' example: 10.0 nullable: true fuel: type: string description: diesel|gasoline|lpg. example: diesel nullable: true currency: type: string description: 'ISO 4217.' example: RUB nullable: true locale: type: string description: 'Язык названий стран.' example: ru nullable: true required: - waypoints security: [] /api/vansky/weather: get: summary: 'VanSky weather for all countries' operationId: vanSkyWeatherForAllCountries description: 'Все страны — сводные данные для таблицы / карты. Ответ ~900 КБ, кешируется на 1 час.' parameters: [] responses: 200: description: 'Success (truncated)' content: application/json: schema: type: object example: 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: 162 updated_at: '2026-08-27T02:00:00+03:00' source: 'Open-Meteo (api.open-meteo.com)' properties: data: type: array example: - 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 items: type: object properties: country_code: type: string example: DE country_slug: type: string example: germany van_score: type: integer example: 90 temp_day: type: number example: 24.1 temp_night: type: number example: 14.3 solar_kwh: type: number example: 2.8 sea_temp: type: number example: 18.2 is_coastal: type: boolean example: true label: type: string example: ideal count: type: integer example: 162 updated_at: type: string example: '2026-08-27T02:00:00+03:00' source: type: string example: 'Open-Meteo (api.open-meteo.com)' tags: - Endpoints security: [] '/api/vansky/weather/{code}': get: summary: 'VanSky weather for one country' operationId: vanSkyWeatherForOneCountry description: 'Подробные данные одной страны (ISO 3166-1 alpha-2).' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: code: DE marine: sea_temp: 19.2 wave_dir: 283 swell_dir: 334 wave_height: 1.28 wave_period: 4.3 swell_height: 0 swell_period: 4.6 wind_wave_dir: 282 wind_wave_height: 1.28 wind_wave_period: 4.3 region: europe weather: sunset: '2026-09-01T17:55' uv_max: null sunrise: '2026-09-01T04:17' humidity: 81 temp_day: 23 wind_dir: 263 wind_max: 15.9 dew_point: 12.9 precip_sum: 0.7 temp_night: 15.1 cloud_cover: 90 temp_current: 16.2 weather_code: 51 feels_like_day: 21.7 peak_sun_hours: 4.1 sunshine_hours: 11.2 wind_gusts_max: 41.4 precip_prob_max: 0 feels_like_night: 14.5 feels_like_current: 15.1 shortwave_radiation_sum: 14.75 forecast: - date: '2026-09-01' temp_day: 23 solar_kwh: 1.7 van_score: 92 temp_night: 15.1 drive_score: 100 score_label: ideal sleep_score: 90 weather_code: 51 - date: '2026-09-02' temp_day: 21.6 solar_kwh: 1.3 van_score: 92 temp_night: 13.5 drive_score: 100 score_label: ideal sleep_score: 88 weather_code: 3 - date: '2026-09-03' temp_day: 22.5 solar_kwh: 1.3 van_score: 92 temp_night: 14.9 drive_score: 100 score_label: ideal sleep_score: 86 weather_code: 3 - date: '2026-09-04' temp_day: 26.6 solar_kwh: 1.2 van_score: 88 temp_night: 17.2 drive_score: 94 score_label: ideal sleep_score: 82 weather_code: 65 - date: '2026-09-05' temp_day: 21.2 solar_kwh: 1.5 van_score: 89 temp_night: 14.1 drive_score: 98 score_label: ideal sleep_score: 87 weather_code: 51 - date: '2026-09-06' temp_day: 24.3 solar_kwh: 2 van_score: 92 temp_night: 11.9 drive_score: 100 score_label: ideal sleep_score: 84 weather_code: 2 - date: '2026-09-07' temp_day: 26.7 solar_kwh: 1.6 van_score: 92 temp_night: 15.2 drive_score: 100 score_label: ideal sleep_score: 84 weather_code: 2 sea_score: null solar_kwh: 1.7 van_score: 92 confidence: high fetched_at: '2026-09-01T03:12:05.773449Z' is_coastal: true week_score: 88 band_counts: hard: 0 ideal: 1698 extreme: 0 acceptable: 1 comfortable: 76 drive_score: 100 score_label: ideal sleep_score: 85 solar_score: 36 drive_window: null awning_status: caution best_move_day: date: '2026-09-01' temp_day: 23 solar_kwh: 1.7 van_score: 94 temp_night: 15.1 drive_score: 100 score_label: ideal sleep_score: 90 weather_code: 51 sample_points: 1775 typical_score: 87 ideal_coverage: 100 sample_regions: 16 best_area_score: 89 recommendations: - key: vansky.rec.awning_caution type: warning params: gusts: 41.4 - key: vansky.rec.night_ideal type: success params: temp: 16.1 - key: vansky.rec.day_comfortable type: success params: temp: 23.6 condensation_risk: medium aggregation_version: 2 comfortable_coverage: 100 updated_at: '2026-09-01T03:12:58+03:00' source: 'Open-Meteo (api.open-meteo.com)' _attribution: data_source: openvan.camp license: 'CC BY 4.0' attribution_url: 'https://openvan.camp/' attribution_html: 'Data: OpenVan.camp (CC BY 4.0)' properties: data: type: object properties: code: type: string example: DE marine: type: object properties: sea_temp: type: number example: 19.2 wave_dir: type: integer example: 283 swell_dir: type: integer example: 334 wave_height: type: number example: 1.28 wave_period: type: number example: 4.3 swell_height: type: integer example: 0 swell_period: type: number example: 4.6 wind_wave_dir: type: integer example: 282 wind_wave_height: type: number example: 1.28 wind_wave_period: type: number example: 4.3 region: type: string example: europe weather: type: object properties: sunset: type: string example: '2026-09-01T17:55' uv_max: type: string example: null nullable: true sunrise: type: string example: '2026-09-01T04:17' humidity: type: integer example: 81 temp_day: type: integer example: 23 wind_dir: type: integer example: 263 wind_max: type: number example: 15.9 dew_point: type: number example: 12.9 precip_sum: type: number example: 0.7 temp_night: type: number example: 15.1 cloud_cover: type: integer example: 90 temp_current: type: number example: 16.2 weather_code: type: integer example: 51 feels_like_day: type: number example: 21.7 peak_sun_hours: type: number example: 4.1 sunshine_hours: type: number example: 11.2 wind_gusts_max: type: number example: 41.4 precip_prob_max: type: integer example: 0 feels_like_night: type: number example: 14.5 feels_like_current: type: number example: 15.1 shortwave_radiation_sum: type: number example: 14.75 forecast: type: array example: - date: '2026-09-01' temp_day: 23 solar_kwh: 1.7 van_score: 92 temp_night: 15.1 drive_score: 100 score_label: ideal sleep_score: 90 weather_code: 51 - date: '2026-09-02' temp_day: 21.6 solar_kwh: 1.3 van_score: 92 temp_night: 13.5 drive_score: 100 score_label: ideal sleep_score: 88 weather_code: 3 - date: '2026-09-03' temp_day: 22.5 solar_kwh: 1.3 van_score: 92 temp_night: 14.9 drive_score: 100 score_label: ideal sleep_score: 86 weather_code: 3 - date: '2026-09-04' temp_day: 26.6 solar_kwh: 1.2 van_score: 88 temp_night: 17.2 drive_score: 94 score_label: ideal sleep_score: 82 weather_code: 65 - date: '2026-09-05' temp_day: 21.2 solar_kwh: 1.5 van_score: 89 temp_night: 14.1 drive_score: 98 score_label: ideal sleep_score: 87 weather_code: 51 - date: '2026-09-06' temp_day: 24.3 solar_kwh: 2 van_score: 92 temp_night: 11.9 drive_score: 100 score_label: ideal sleep_score: 84 weather_code: 2 - date: '2026-09-07' temp_day: 26.7 solar_kwh: 1.6 van_score: 92 temp_night: 15.2 drive_score: 100 score_label: ideal sleep_score: 84 weather_code: 2 items: type: object properties: date: type: string example: '2026-09-01' temp_day: type: integer example: 23 solar_kwh: type: number example: 1.7 van_score: type: integer example: 92 temp_night: type: number example: 15.1 drive_score: type: integer example: 100 score_label: type: string example: ideal sleep_score: type: integer example: 90 weather_code: type: integer example: 51 sea_score: type: string example: null nullable: true solar_kwh: type: number example: 1.7 van_score: type: integer example: 92 confidence: type: string example: high fetched_at: type: string example: '2026-09-01T03:12:05.773449Z' is_coastal: type: boolean example: true week_score: type: integer example: 88 band_counts: type: object properties: hard: type: integer example: 0 ideal: type: integer example: 1698 extreme: type: integer example: 0 acceptable: type: integer example: 1 comfortable: type: integer example: 76 drive_score: type: integer example: 100 score_label: type: string example: ideal sleep_score: type: integer example: 85 solar_score: type: integer example: 36 drive_window: type: string example: null nullable: true awning_status: type: string example: caution best_move_day: type: object properties: date: type: string example: '2026-09-01' temp_day: type: integer example: 23 solar_kwh: type: number example: 1.7 van_score: type: integer example: 94 temp_night: type: number example: 15.1 drive_score: type: integer example: 100 score_label: type: string example: ideal sleep_score: type: integer example: 90 weather_code: type: integer example: 51 sample_points: type: integer example: 1775 typical_score: type: integer example: 87 ideal_coverage: type: integer example: 100 sample_regions: type: integer example: 16 best_area_score: type: integer example: 89 recommendations: type: array example: - key: vansky.rec.awning_caution type: warning params: gusts: 41.4 - key: vansky.rec.night_ideal type: success params: temp: 16.1 - key: vansky.rec.day_comfortable type: success params: temp: 23.6 items: type: object properties: key: type: string example: vansky.rec.awning_caution type: type: string example: warning params: type: object properties: gusts: type: number example: 41.4 condensation_risk: type: string example: medium aggregation_version: type: integer example: 2 comfortable_coverage: type: integer example: 100 updated_at: type: string example: '2026-09-01T03:12:58+03:00' source: type: string example: 'Open-Meteo (api.open-meteo.com)' _attribution: type: object properties: data_source: type: string example: openvan.camp license: type: string example: 'CC BY 4.0' attribution_url: type: string example: 'https://openvan.camp/' attribution_html: type: string example: 'Data: OpenVan.camp (CC BY 4.0)' 404: description: 'Not found' content: application/json: schema: type: object example: error: 'Country not found or not supported' properties: error: type: string example: 'Country not found or not supported' tags: - Endpoints security: [] parameters: - in: path name: code description: 'ISO 3166-1 alpha-2 код страны.' example: DE required: true schema: type: string /api/events: get: summary: 'List events' operationId: listEvents description: "Returns a paginated list of vanlife events (exhibitions, festivals, meetups, road trips).\nFilter by status, type, country, or search by name." parameters: - in: query name: locale description: 'Language code for localized names. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en required: false schema: type: string description: 'Language code for localized names. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en - in: query name: status description: 'Filter by event status. One of: `upcoming`, `ongoing`, `past`, `all`. Defaults to `upcoming`.' example: upcoming required: false schema: type: string description: 'Filter by event status. One of: `upcoming`, `ongoing`, `past`, `all`. Defaults to `upcoming`.' example: upcoming - in: query name: type description: 'Filter by event type. One of: `expo`, `festival`, `forum`, `meetup`, `roadtrip`.' example: festival required: false schema: type: string description: 'Filter by event type. One of: `expo`, `festival`, `forum`, `meetup`, `roadtrip`.' example: festival - in: query name: country description: '2-letter ISO country code.' example: DE required: false schema: type: string description: '2-letter ISO country code.' example: DE - in: query name: search description: 'Text search by event name.' example: 'Adventure Northside' required: false schema: type: string description: 'Text search by event name.' example: 'Adventure Northside' - in: query name: page description: 'Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'Page number. Defaults to 1.' example: 1 - in: query name: limit description: 'Results per page (max 100). Defaults to 30.' example: 30 required: false schema: type: integer description: 'Results per page (max 100). Defaults to 30.' example: 30 responses: 200: description: Success content: application/json: schema: type: object example: 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 properties: events: type: array example: - 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' items: type: object properties: id: type: integer example: 960 slug: type: string example: adventure-northside-2026 event_name: type: string example: 'Adventure Northside 2026' event_type: type: string example: festival event_type_emoji: type: string example: 🎉 start_date: type: string example: '2026-09-18' end_date: type: string example: '2026-09-20' city: type: string example: Basthorst country_code: type: string example: DE country: type: object properties: code: type: string example: de slug: type: string example: germany name: type: string example: Germany flag_emoji: type: string example: 🇩🇪 status: type: string example: upcoming url: type: string example: 'https://openvan.camp/en/event/adventure-northside-2026' pagination: type: object properties: total: type: integer example: 48 page: type: integer example: 1 limit: type: integer example: 30 pages: type: integer example: 2 tags: - Events security: [] '/api/event/{slug}': get: summary: 'Get event details' operationId: getEventDetails description: 'Returns full details for a single vanlife event by slug, including location, description, and social links.' parameters: - in: query name: locale description: 'Language for localized content. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`.' example: en required: false schema: type: string description: 'Language for localized content. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`.' example: en responses: 200: description: Success content: application/json: schema: type: object example: 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' properties: id: type: integer example: 960 slug: type: string example: adventure-northside-2026 event_name: type: string example: 'Adventure Northside 2026' event_type: type: string example: festival event_type_emoji: type: string example: 🎉 start_date: type: string example: '2026-09-18' end_date: type: string example: '2026-09-20' city: type: string example: Basthorst country_code: type: string example: DE description: type: string example: "Northern Germany's Overland & Self-build expo and festival..." official_url: type: string example: 'https://adventurenorthside.de/' image_url: type: string example: 'https://...' status: type: string example: upcoming url: type: string example: 'https://openvan.camp/en/event/adventure-northside-2026' 404: description: 'Not found' content: application/json: schema: type: object example: message: 'No query results for model [App\Models\Event].' properties: message: type: string example: 'No query results for model [App\Models\Event].' tags: - Events security: [] parameters: - in: path name: slug description: 'The event slug.' example: adventure-northside-2026 required: true schema: type: string '/api/event/{slug}/articles': get: summary: 'Get event articles' operationId: getEventArticles description: "Returns source articles linked to this event.\nWhen `locale` is provided, attempts to return only articles in that language.\nIf no articles match the requested locale, **all articles are returned** as a fallback\n(they may be in the original source language, e.g. Japanese or German).\nThe `language` field on each article indicates the actual language of the source." parameters: - in: query name: locale description: 'Language code to filter articles by source language. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en required: false schema: type: string description: 'Language code to filter articles by source language. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en responses: 200: description: Success content: application/json: schema: type: array items: type: object properties: id: type: integer example: 1001 title: type: string example: 'Adventure Northside 2026 opens its doors' image_url: type: string example: 'https://...' published_at: type: string example: '2026-03-11T10:00:00+00:00' source_name: type: string example: 'CamperVan Magazine' original_url: type: string example: 'https://...' language: type: string example: en example: - 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 tags: - Events security: [] parameters: - in: path name: slug description: 'The event slug.' example: adventure-northside-2026 required: true schema: type: string /api/fuel/prices: get: summary: 'Get fuel prices' operationId: getFuelPrices description: "Returns current retail fuel prices for all supported countries.\nPrice keys follow FuelGradeCatalog::ORDER plus the legacy `premium` alias.\nData is updated weekly from 45+ official government sources and independent aggregators.\n\nPrices are weighted averages from multiple sources per country. The `sources` array\nlists all contributing data providers (sorted by trust weight, highest first).\n\n**License:** CC BY 4.0 — free to use with attribution to [OpenVan.camp](https://openvan.camp)." parameters: - in: query name: country description: 'Optional ISO 3166-1 alpha-2 code to return a single country instead of all. Unknown codes return 404.' example: "tr\n\nПоле `unit` — единица, в которой опубликована цена страны:\n`liter`, `gallon` (US, 3.78541 л) или `imperial_gallon` (4.54609 л,\nбывшие британские территории). Значения отдаются в том виде, в каком их\nпубликует источник, — приводить к литрам должен потребитель." required: false schema: type: string description: 'Optional ISO 3166-1 alpha-2 code to return a single country instead of all. Unknown codes return 404.' example: "tr\n\nПоле `unit` — единица, в которой опубликована цена страны:\n`liter`, `gallon` (US, 3.78541 л) или `imperial_gallon` (4.54609 л,\nбывшие британские территории). Значения отдаются в том виде, в каком их\nпубликует источник, — приводить к литрам должен потребитель." responses: 200: description: Success content: application/json: schema: type: object example: 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.0 cng: null e85: null kerosene: null premium: null fetched_at: '2026-08-22T08:50:59+03:00' sources: - Fuelo.net - 'EU Weekly Oil Bulletin' - Cargopedia.net sources_count: 3 is_excluded: false meta: total_countries: 142 updated_at: '2026-08-22 08:51:00' cache_ttl_hours: 6 properties: success: type: boolean example: true data: type: object properties: DE: type: object properties: country_code: type: string example: DE country_name: type: string example: Germany region: type: string example: europe currency: type: string example: EUR local_currency: type: string example: EUR unit: type: string example: liter prices: type: object properties: gasoline_regular: type: string example: null nullable: true gasoline: type: number example: 2.1313 gasoline_premium: type: string example: null nullable: true gasoline_super: type: string example: null nullable: true diesel_regular: type: string example: null nullable: true diesel: type: number example: 2.2845 diesel_premium: type: string example: null nullable: true lpg: type: number example: 1.113 cng: type: string example: null nullable: true e85: type: string example: null nullable: true kerosene: type: string example: null nullable: true premium: type: string example: null nullable: true price_changes: type: object properties: gasoline_regular: type: string example: null nullable: true gasoline: type: number example: -0.02 gasoline_premium: type: string example: null nullable: true gasoline_super: type: string example: null nullable: true diesel_regular: type: string example: null nullable: true diesel: type: number example: 0.01 diesel_premium: type: string example: null nullable: true lpg: type: number example: 0.0 cng: type: string example: null nullable: true e85: type: string example: null nullable: true kerosene: type: string example: null nullable: true premium: type: string example: null nullable: true fetched_at: type: string example: '2026-08-22T08:50:59+03:00' sources: type: array example: - Fuelo.net - 'EU Weekly Oil Bulletin' - Cargopedia.net items: type: string sources_count: type: integer example: 3 is_excluded: type: boolean example: false meta: type: object properties: total_countries: type: integer example: 142 updated_at: type: string example: '2026-08-22 08:51:00' cache_ttl_hours: type: integer example: 6 tags: - 'Fuel Prices' security: [] /api/stories: get: summary: 'List stories' operationId: listStories description: "Returns a paginated list of vanlife news stories in the requested language.\nTitles and summaries are translated; `sources` are original-language articles." parameters: - in: query name: locale description: 'Language for localized titles and summaries. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en required: false schema: type: string description: 'Language for localized titles and summaries. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en - in: query name: category description: 'Filter by category slug. One of: `lifestyle`, `industry`, `incident`, `opening`, `closing`, `law`, `builds`, `festival`, `expo`, `review`, `ban`, `other`.' example: festival required: false schema: type: string description: 'Filter by category slug. One of: `lifestyle`, `industry`, `incident`, `opening`, `closing`, `law`, `builds`, `festival`, `expo`, `review`, `ban`, `other`.' example: festival - in: query name: country description: '2-letter ISO country code to filter by associated country.' example: DE required: false schema: type: string description: '2-letter ISO country code to filter by associated country.' example: DE - in: query name: search description: 'Full-text search by story title.' example: 'vanlife festival' required: false schema: type: string description: 'Full-text search by story title.' example: 'vanlife festival' - in: query name: page description: 'Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'Page number. Defaults to 1.' example: 1 - in: query name: limit description: 'Results per page (max 50). Defaults to 20.' example: 20 required: false schema: type: integer description: 'Results per page (max 50). Defaults to 20.' example: 20 responses: 200: description: Success content: application/json: schema: type: object example: 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 properties: stories: type: array example: - 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' items: type: object properties: slug: type: string example: adac-camper-des-jahres-der-wettbewerb-fuer title: type: string example: "ADAC launches 'Camper of the Year' competition for motorhome drivers" summary: type: string example: "ADAC is holding the national 'Camper des Jahres 2026' competition for motorhome owners..." image_url: type: string example: 'https://...' category: type: object properties: slug: type: string example: festival name: type: string example: Festivals countries: type: array example: - code: de name: Germany flag_emoji: 🇩🇪 items: type: object properties: code: type: string example: de name: type: string example: Germany flag_emoji: type: string example: 🇩🇪 first_published_at: type: string example: '2026-01-22T11:00:00+03:00' articles_count: type: integer example: 5 url: type: string example: 'https://openvan.camp/en/news/festival/adac-camper-des-jahres-der-wettbewerb-fuer' pagination: type: object properties: total: type: integer example: 120 page: type: integer example: 1 limit: type: integer example: 20 pages: type: integer example: 6 tags: - Stories security: [] '/api/story/{slug}': get: summary: 'Get story details' operationId: getStoryDetails description: "Returns full details for a single news story including all source articles.\nThe `sources` array contains original publisher articles with direct links." parameters: - in: query name: locale description: 'Language for localized title and summary. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en required: false schema: type: string description: 'Language for localized title and summary. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: en responses: 200: description: Success content: application/json: schema: type: object example: 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://...' properties: slug: type: string example: adac-camper-des-jahres-der-wettbewerb-fuer title: type: string example: "ADAC launches 'Camper of the Year' competition for motorhome drivers" summary: type: string example: "ADAC is holding the national 'Camper des Jahres 2026' competition for motorhome owners..." image_url: type: string example: 'https://...' category: type: object properties: slug: type: string example: festival name: type: string example: Festivals countries: type: array example: - code: de name: Germany flag_emoji: 🇩🇪 items: type: object properties: code: type: string example: de name: type: string example: Germany flag_emoji: type: string example: 🇩🇪 first_published_at: type: string example: '2026-01-22T11:00:00+03:00' last_updated_at: type: string example: '2026-07-04T04:16:47+03:00' articles_count: type: integer example: 5 url: type: string example: 'https://openvan.camp/en/news/festival/adac-camper-des-jahres-der-wettbewerb-fuer' sources: type: array example: - 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://...' items: type: object properties: title: type: string example: 'Nürburgring: Bundesweiter Wettbewerb «Camper des Jahres»' original_url: type: string example: 'https://www.blick-aktuell.de/Berichte/...' source_name: type: string example: 'BLICK aktuell' published_at: type: string example: '2026-04-30T09:24:20+03:00' language: type: string example: de image_url: type: string example: 'https://...' 404: description: 'Not found' content: application/json: schema: type: object example: error: 'Story not found.' properties: error: type: string example: 'Story not found.' tags: - Stories security: [] parameters: - in: path name: slug description: 'The story slug.' example: adac-camper-des-jahres-der-wettbewerb-fuer required: true schema: type: string /api/news/search: get: summary: 'Semantic news search (RAG)' operationId: semanticNewsSearchRAG description: "Semantic search over news via the same engine as the /{locale}/search page\n(SemanticSearchService: Jina embeddings + pgvector). Returns matching news\nstories ranked by similarity. Story summary shape matches /stories." parameters: - in: query name: q description: 'Search query.' example: 'ford camper 2026' required: true schema: type: string description: 'Search query.' example: 'ford camper 2026' - in: query name: locale description: 'Language for localized titles/summaries. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: ru required: false schema: type: string description: 'Language for localized titles/summaries. One of: `en`, `ru`, `de`, `fr`, `es`, `pt`, `tr`. Defaults to `en`.' example: ru - in: query name: limit description: 'Max results (1-15). Defaults to 8.' example: 8 required: false schema: type: integer description: 'Max results (1-15). Defaults to 8.' example: 8 responses: 200: description: '' content: application/json: schema: type: object example: 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: notable-camper-vans-weve-found-2026-far-gear title: 'Самые заметные кемперы 2026 года: обзор' summary: 'В 2026 году сегмент кемперов активно развивается: появляются новые электрические модели от Hyundai, Kia и Volkswagen, а также многочисленные доработки от сторонних производителей. Среди традиционных платформ по-прежнему популярны Mercedes Sprinter и Ram ProMaster.' image_url: 'https://www.gearpatrol.com/wp-content/uploads/sites/2/2026/08/Camper-Vans-Roundup-Lead.webp' category: slug: industry name: Индустрия countries: [] first_published_at: '2026-08-12T20:04:31+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/notable-camper-vans-weve-found-2026-far-gear' score: 0.547 - slug: new-carinspired-fiberglass-camper-almost-color title: 'Новый стеклопластиковый кемпер Outranger можно заказать в любом цвете RAL' summary: 'Компания Motsmann Engineering из Орегона представила кемпер Outranger, который отличается стеклопластиковым кузовом, собираемым из шести панелей, и модульной рамой на болтах. Кемпер весит менее 1500 фунтов, что позволяет буксировать его даже компактным пикапам, таким как Ford Maverick. Доступен в 216 цветах RAL, включая нестандартные. Базовая комплектация включает литий-железо-фосфатную батарею на 200 А·ч, а опционально доступны солнечные панели, инвертор и кондиционер.' image_url: 'https://images-stag.jazelc.com/uploads/theautopian-m2en/Fiberglass_Camper_TS-1.jpg' category: slug: industry name: Индустрия countries: - code: us name: США flag_emoji: 🇺🇸 first_published_at: '2026-08-24T18:55:42+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/new-carinspired-fiberglass-camper-almost-color' score: 0.543 - slug: el-mejor-motorhome-de-2026-que-tiene-de-especial 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://supertruck.com.ar/wp-content/uploads/2026/07/mejor-motorhome-de-2026-carado-t457-5.jpg' category: slug: industry name: Индустрия countries: - code: de name: Германия flag_emoji: 🇩🇪 first_published_at: '2026-07-26T08:10:47+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/el-mejor-motorhome-de-2026-que-tiene-de-especial' score: 0.529 timing_ms: 568 _attribution: data_source: openvan.camp license: 'CC BY 4.0' attribution_url: 'https://openvan.camp/' attribution_html: 'Data: OpenVan.camp (CC BY 4.0)' properties: results: type: array example: - 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: notable-camper-vans-weve-found-2026-far-gear title: 'Самые заметные кемперы 2026 года: обзор' summary: 'В 2026 году сегмент кемперов активно развивается: появляются новые электрические модели от Hyundai, Kia и Volkswagen, а также многочисленные доработки от сторонних производителей. Среди традиционных платформ по-прежнему популярны Mercedes Sprinter и Ram ProMaster.' image_url: 'https://www.gearpatrol.com/wp-content/uploads/sites/2/2026/08/Camper-Vans-Roundup-Lead.webp' category: slug: industry name: Индустрия countries: [] first_published_at: '2026-08-12T20:04:31+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/notable-camper-vans-weve-found-2026-far-gear' score: 0.547 - slug: new-carinspired-fiberglass-camper-almost-color title: 'Новый стеклопластиковый кемпер Outranger можно заказать в любом цвете RAL' summary: 'Компания Motsmann Engineering из Орегона представила кемпер Outranger, который отличается стеклопластиковым кузовом, собираемым из шести панелей, и модульной рамой на болтах. Кемпер весит менее 1500 фунтов, что позволяет буксировать его даже компактным пикапам, таким как Ford Maverick. Доступен в 216 цветах RAL, включая нестандартные. Базовая комплектация включает литий-железо-фосфатную батарею на 200 А·ч, а опционально доступны солнечные панели, инвертор и кондиционер.' image_url: 'https://images-stag.jazelc.com/uploads/theautopian-m2en/Fiberglass_Camper_TS-1.jpg' category: slug: industry name: Индустрия countries: - code: us name: США flag_emoji: 🇺🇸 first_published_at: '2026-08-24T18:55:42+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/new-carinspired-fiberglass-camper-almost-color' score: 0.543 - slug: el-mejor-motorhome-de-2026-que-tiene-de-especial 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://supertruck.com.ar/wp-content/uploads/2026/07/mejor-motorhome-de-2026-carado-t457-5.jpg' category: slug: industry name: Индустрия countries: - code: de name: Германия flag_emoji: 🇩🇪 first_published_at: '2026-07-26T08:10:47+03:00' articles_count: 1 url: 'https://openvan.camp/ru/news/industry/el-mejor-motorhome-de-2026-que-tiene-de-especial' score: 0.529 items: type: object properties: slug: type: string example: panoramic-ford-f-camper-truck-costs-fraction title: type: string example: 'Supertramp представила кемпер Paragon на базе Ford F-350' summary: type: string example: 'Компания Supertramp анонсировала новую модель кемпера Paragon на шасси Ford F-350. Базовая цена составляет 199 000 долларов, что значительно ниже конкурентов, таких как Earthroamer (от 825 000 долларов) и Winnebago Arka (330 000 долларов). Модель оснащена композитным модулем с вакуумной инфузией, спальными местами на четыре человека и опциональной палаткой на крыше для шести человек. Стандартная комплектация включает литий-ионную батарею на 270 А·ч, инвертор на 3000 Вт и солнечную систему на 660 Вт.' image_url: type: string example: '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: type: object properties: slug: type: string example: industry name: type: string example: Индустрия countries: type: array example: [] first_published_at: type: string example: '2026-06-05T04:35:09+03:00' articles_count: type: integer example: 1 url: type: string example: 'https://openvan.camp/ru/news/industry/panoramic-ford-f-camper-truck-costs-fraction' score: type: number example: 0.562 timing_ms: type: integer example: 568 _attribution: type: object properties: data_source: type: string example: openvan.camp license: type: string example: 'CC BY 4.0' attribution_url: type: string example: 'https://openvan.camp/' attribution_html: type: string example: 'Data: OpenVan.camp (CC BY 4.0)' tags: - Stories security: [] /api/news/digest: get: summary: 'Daily news digest (raw content)' operationId: dailyNewsDigestrawContent description: "Returns the structured evening news digest for the requested locale,\nassembled once per evening by the site. Consumers (site social channels," parameters: - in: query name: locale description: 'Digest language. Currently `ru` or `en`. Defaults to `ru`.' example: ru required: false schema: type: string description: 'Digest language. Currently `ru` or `en`. Defaults to `ru`.' example: ru responses: 200: description: Success content: application/json: schema: type: object example: 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' properties: locale: type: string example: ru date: type: string example: '2026-07-25' intro: type: string example: 'Дороги сегодня подкинули всё…' groups: type: array example: - key: incident title: '⚠️ Происшествия' items: - id: 123 flag: 🇩🇪 hook: Заголовок-зацепка detail: 'Деталь сюжета' url: 'https://openvan.camp/ru/news/incident/slug' items: type: object properties: key: type: string example: incident title: type: string example: '⚠️ Происшествия' items: type: array example: - id: 123 flag: 🇩🇪 hook: Заголовок-зацепка detail: 'Деталь сюжета' url: 'https://openvan.camp/ru/news/incident/slug' items: type: object properties: id: type: integer example: 123 flag: type: string example: 🇩🇪 hook: type: string example: Заголовок-зацепка detail: type: string example: 'Деталь сюжета' url: type: string example: 'https://openvan.camp/ru/news/incident/slug' 204: description: 'No digest yet' content: text/plain: schema: type: string example: '' tags: - Stories security: [] /api/vanbasket/countries: get: summary: 'Get all countries with VanBasket index.' operationId: getAllCountriesWithVanBasketIndex description: "Returns food price index for 90+ countries.\nWorld average = 100. Above 100 = more expensive, below 100 = cheaper." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: DE: country_code: DE country_name: Germany vanbasket_index: 124.9 pct_vs_world: 24.9 meta: total_countries: 92 properties: success: type: boolean example: true data: type: object properties: DE: type: object properties: country_code: type: string example: DE country_name: type: string example: Germany vanbasket_index: type: number example: 124.9 pct_vs_world: type: number example: 24.9 meta: type: object properties: total_countries: type: integer example: 92 tags: - 'VanBasket Food Price Index' security: [] /api/vanbasket/compare: get: summary: 'Compare food prices between two countries.' operationId: compareFoodPricesBetweenTwoCountries description: '' parameters: - in: query name: from description: 'ISO 3166-1 alpha-2 code of home country.' example: DE required: true schema: type: string description: 'ISO 3166-1 alpha-2 code of home country.' example: DE - in: query name: to description: 'ISO 3166-1 alpha-2 code of destination country.' example: TR required: true schema: type: string description: 'ISO 3166-1 alpha-2 code of destination country.' example: TR responses: 200: description: '' content: application/json: schema: type: object example: success: true data: from: country_code: DE country_name: Germany vanbasket_index: 124.9 to: country_code: TR country_name: Turkey vanbasket_index: 88.0 diff_percent: -29.5 budget_100: 70 cheaper: true properties: success: type: boolean example: true data: type: object properties: from: type: object properties: country_code: type: string example: DE country_name: type: string example: Germany vanbasket_index: type: number example: 124.9 to: type: object properties: country_code: type: string example: TR country_name: type: string example: Turkey vanbasket_index: type: number example: 88.0 diff_percent: type: number example: -29.5 budget_100: type: integer example: 70 cheaper: type: boolean example: true tags: - 'VanBasket Food Price Index' security: [] '/api/vanbasket/countries/{code}': get: summary: 'Get VanBasket country details' operationId: getVanBasketCountryDetails description: 'Detailed data for a single country including historical snapshots.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: country: country_code: DE vanbasket_index: 124.9 snapshots: - snapshot_date: '2021-01-01' vanbasket_index: 124.9 properties: success: type: boolean example: true data: type: object properties: country: type: object properties: country_code: type: string example: DE vanbasket_index: type: number example: 124.9 snapshots: type: array example: - snapshot_date: '2021-01-01' vanbasket_index: 124.9 items: type: object properties: snapshot_date: type: string example: '2021-01-01' vanbasket_index: type: number example: 124.9 tags: - 'VanBasket Food Price Index' security: [] parameters: - in: path name: code description: 'ISO 3166-1 alpha-2 country code.' example: DE required: true schema: type: string /api/visa/check: get: summary: 'Check a passport against a destination.' operationId: checkAPassportAgainstADestination description: "Returns the stay rule (days, counting window, whether a visa run resets\nthe counter), the entry mode, and the vehicle import rule for the same\ndestination.\n\nIf the country belongs to a shared-counter zone, the stay rule is the\nzone's — entering Spain spends Schengen days, not \"Spanish\" ones — and\n`counted_against` names the place the counter belongs to." parameters: - in: query name: passport description: 'ISO 3166-1 alpha-2 code of the passport.' example: RU required: true schema: type: string description: 'ISO 3166-1 alpha-2 code of the passport.' example: RU - in: query name: destination description: 'ISO alpha-2 code, slug or zone code.' example: TR required: true schema: type: string description: 'ISO alpha-2 code, slug or zone code.' example: TR - in: query name: weight description: 'Vehicle weight class for the vehicle rule: le35 (≤3.5t) or gt35.' example: le35 required: false schema: type: string description: 'Vehicle weight class for the vehicle rule: le35 (≤3.5t) or gt35.' example: le35 - in: query name: plate description: 'Vehicle plate origin for the vehicle rule: eu, non_eu, eaeu, third.' example: third required: false schema: type: string description: 'Vehicle plate origin for the vehicle rule: eu, non_eu, eaeu, third.' example: third - in: query name: locale description: 'Language of place names, one of ru/en/de/es/fr/pt/tr. Defaults to en.' example: en required: false schema: type: string description: 'Language of place names, one of ru/en/de/es/fr/pt/tr. Defaults to en.' example: en responses: 200: description: '' content: application/json: schema: type: object example: 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 properties: success: type: boolean example: true data: type: object properties: passport: type: object properties: code: type: string example: RU name: type: string example: Russia destination: type: object properties: code: type: string example: TR name: type: string example: Turkey kind: type: string example: country zone: type: string example: null nullable: true entry_mode: type: string example: visa_free stay: type: object properties: visa_type: type: string example: visa_free max_continuous: type: integer example: 90 max_total: type: integer example: 90 window: type: string example: rolling window_days: type: integer example: 180 visa_run: type: boolean example: false confidence: type: string example: high source_url: type: string example: 'https://www.mfa.gov.tr/visa-information-for-foreigners.en.mfa' note: type: string example: 'Безвиз 90/180.' layer: type: string example: curated vehicle: type: object properties: max_days: type: string example: null nullable: true basis: type: string example: tied_to_person green_card: type: string example: required confidence: type: string example: high 422: description: '' content: application/json: schema: type: object example: success: false error: 'Parameters "passport" and "destination" are required.' properties: success: type: boolean example: false error: type: string example: 'Parameters "passport" and "destination" are required.' tags: - 'Visa & Border Rules' security: [] /api/visa/route: get: summary: 'Visa and vehicle rules for a whole route, in one request.' operationId: visaAndVehicleRulesForAWholeRouteInOneRequest description: "Built for the fuel-cost calculator: it knows the countries a trip crosses\nbut nothing about the traveller, so the answer has to cover several\npassports at once. Rows are collapsed by rule — passports that get the\nsame treatment share one row instead of repeating the same numbers.\n\nCountries sharing a counter (Schengen and the like) are merged into one\nleg: adding up \"Bulgarian\" and \"Croatian\" days would be plainly wrong." parameters: - in: query name: t description: 'Countries in travel order, comma separated ISO alpha-2 codes, slugs or zone codes. Up to 12.' example: 'RU,GE,TR' required: true schema: type: string description: 'Countries in travel order, comma separated ISO alpha-2 codes, slugs or zone codes. Up to 12.' example: 'RU,GE,TR' - in: query name: p description: 'Passports to answer for, comma separated, up to 10. Defaults to the set matching `locale`, and `meta.assumed_passports` then says so.' example: 'RU,BY,KZ' required: false schema: type: string description: 'Passports to answer for, comma separated, up to 10. Defaults to the set matching `locale`, and `meta.assumed_passports` then says so.' example: 'RU,BY,KZ' - in: query name: w description: 'Vehicle weight class: le35 (≤3.5t) or gt35.' example: le35 required: false schema: type: string description: 'Vehicle weight class: le35 (≤3.5t) or gt35.' example: le35 - in: query name: plate description: 'Plate origin for the vehicle rule: eu, non_eu, eaeu, third.' example: third required: false schema: type: string description: 'Plate origin for the vehicle rule: eu, non_eu, eaeu, third.' example: third - in: query name: locale description: 'Language of names and labels, one of ru/en/de/es/fr/pt/tr. Defaults to en.' example: ru required: false schema: type: string description: 'Language of names and labels, one of ru/en/de/es/fr/pt/tr. Defaults to en.' example: ru responses: 200: description: '' content: application/json: schema: type: object example: success: true data: legs: - code: GE name: Georgia slug: georgia flag: ge zone: null members: null rows: - passports: - RU - BY names: - Russia - Belarus mode: visa_free mode_label: 'visa free' days: 365 days_label: '365 d.' duration_label: '1 full year' total: null window_label: 'resets on every entry' visa_run: true confidence: high note: null source_url: 'https://matsne.gov.ge/en/document/view/2867361' vehicle: max_days: 90 days_label: '90 d.' basis_label: 'on every entry' green_card_label: 'insurance is bought at the border' confidence: high source_url: 'https://georgiacb.com/en/articles/customs-procedure-temporary-importation-admission-im-53' note: null registration_hours: null warnings: null bottleneck: code: GE name: Georgia kind: vehicle days: 90 passports: - code: RU name: Russia meta: route: - RU - GE - TR weight: le35 assumed_passports: false properties: success: type: boolean example: true data: type: object properties: legs: type: array example: - code: GE name: Georgia slug: georgia flag: ge zone: null members: null rows: - passports: - RU - BY names: - Russia - Belarus mode: visa_free mode_label: 'visa free' days: 365 days_label: '365 d.' duration_label: '1 full year' total: null window_label: 'resets on every entry' visa_run: true confidence: high note: null source_url: 'https://matsne.gov.ge/en/document/view/2867361' vehicle: max_days: 90 days_label: '90 d.' basis_label: 'on every entry' green_card_label: 'insurance is bought at the border' confidence: high source_url: 'https://georgiacb.com/en/articles/customs-procedure-temporary-importation-admission-im-53' note: null registration_hours: null warnings: null items: type: object properties: code: type: string example: GE name: type: string example: Georgia slug: type: string example: georgia flag: type: string example: ge zone: type: string example: null nullable: true members: type: string example: null nullable: true rows: type: array example: - passports: - RU - BY names: - Russia - Belarus mode: visa_free mode_label: 'visa free' days: 365 days_label: '365 d.' duration_label: '1 full year' total: null window_label: 'resets on every entry' visa_run: true confidence: high note: null source_url: 'https://matsne.gov.ge/en/document/view/2867361' items: type: object properties: passports: type: array example: - RU - BY items: type: string names: type: array example: - Russia - Belarus items: type: string mode: type: string example: visa_free mode_label: type: string example: 'visa free' days: type: integer example: 365 days_label: type: string example: '365 d.' duration_label: type: string example: '1 full year' total: type: string example: null nullable: true window_label: type: string example: 'resets on every entry' visa_run: type: boolean example: true confidence: type: string example: high note: type: string example: null nullable: true source_url: type: string example: 'https://matsne.gov.ge/en/document/view/2867361' vehicle: type: object properties: max_days: type: integer example: 90 days_label: type: string example: '90 d.' basis_label: type: string example: 'on every entry' green_card_label: type: string example: 'insurance is bought at the border' confidence: type: string example: high source_url: type: string example: 'https://georgiacb.com/en/articles/customs-procedure-temporary-importation-admission-im-53' note: type: string example: null nullable: true registration_hours: type: string example: null nullable: true warnings: type: string example: null nullable: true bottleneck: type: object properties: code: type: string example: GE name: type: string example: Georgia kind: type: string example: vehicle days: type: integer example: 90 passports: type: array example: - code: RU name: Russia items: type: object properties: code: type: string example: RU name: type: string example: Russia meta: type: object properties: route: type: array example: - RU - GE - TR items: type: string weight: type: string example: le35 assumed_passports: type: boolean example: false 422: description: '' content: application/json: schema: type: object example: success: false error: 'Parameter "t" must list at least one known destination.' properties: success: type: boolean example: false error: type: string example: 'Parameter "t" must list at least one known destination.' tags: - 'Visa & Border Rules' security: [] /api/visa/rank: get: summary: 'Passport ranking by destinations reachable without a prior visa.' operationId: passportRankingByDestinationsReachableWithoutAPriorVisa description: "Score = visa free + visa on arrival + eTA. The breakdown is returned\nalongside so the number can be checked rather than taken on faith.\nTies share a rank." parameters: - in: query name: limit description: 'How many rows to return, 1..199. Defaults to all.' example: 10 required: false schema: type: integer description: 'How many rows to return, 1..199. Defaults to all.' example: 10 - in: query name: locale description: 'Language of passport names. Defaults to en.' example: en required: false schema: type: string description: 'Language of passport names. Defaults to en.' example: en responses: 200: description: '' content: application/json: schema: type: object example: 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' properties: success: type: boolean example: true data: type: array example: - rank: 1 passport: SG name: Singapore score: 168 visa_free: 130 visa_on_arrival: 30 eta: 8 e_visa: 20 visa_required: 10 items: type: object properties: rank: type: integer example: 1 passport: type: string example: SG name: type: string example: Singapore score: type: integer example: 168 visa_free: type: integer example: 130 visa_on_arrival: type: integer example: 30 eta: type: integer example: 8 e_visa: type: integer example: 20 visa_required: type: integer example: 10 meta: type: object properties: total: type: integer example: 199 scoring: type: string example: 'visa_free + visa_on_arrival + eta' tags: - 'Visa & Border Rules' security: [] /api/visa/history: get: summary: 'Change log of visa and vehicle rules.' operationId: changeLogOfVisaAndVehicleRules description: "One row per changed field, written both by imports and by editors.\nCommercial passport APIs charge for rule history; this one is open." parameters: - in: query name: subject_type description: 'Filter: requirement, window, window_exception, curated_rule, vehicle_rule, place.' example: requirement required: false schema: type: string description: 'Filter: requirement, window, window_exception, curated_rule, vehicle_rule, place.' example: requirement - in: query name: subject_key description: 'Filter by subject, e.g. RU>TR for a pair or TR for a place.' example: RU>TR required: false schema: type: string description: 'Filter by subject, e.g. RU>TR for a pair or TR for a place.' example: RU>TR - in: query name: since description: 'ISO date, only changes on or after it.' example: '2026-01-01' required: false schema: type: string description: 'ISO date, only changes on or after it.' example: '2026-01-01' - in: query name: limit description: '1..500, defaults to 100.' example: 50 required: false schema: type: integer description: '1..500, defaults to 100.' example: 50 responses: 200: description: '' content: application/json: schema: type: object example: 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 properties: success: type: boolean example: true data: type: array example: - 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' items: type: object properties: subject_type: type: string example: requirement subject_key: type: string example: RU>TR field: type: string example: days old_value: type: string example: '60' new_value: type: string example: '90' source: type: string example: import changed_at: type: string example: '2026-07-27T10:00:00+00:00' meta: type: object properties: total: type: integer example: 1 tags: - 'Visa & Border Rules' security: [] '/api/visa/passport/{code}': get: summary: 'All destinations for one passport.' operationId: allDestinationsForOnePassport description: "199 rows resolved through the full chain, sorted by destination name.\nCounts by entry mode are in `meta`." parameters: - in: query name: mode description: 'Filter by entry mode: visa_free, visa_required, e_visa, eta, voa, no_admission.' example: visa_free required: false schema: type: string description: 'Filter by entry mode: visa_free, visa_required, e_visa, eta, voa, no_admission.' example: visa_free - in: query name: locale description: 'Language of place names. Defaults to en.' example: en required: false schema: type: string description: 'Language of place names. Defaults to en.' example: en responses: 200: description: '' content: application/json: schema: type: object example: 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 properties: success: type: boolean example: true data: type: array example: - destination: TR name: Turkey slug: turkey mode: visa_free days: 90 stay: window: rolling window_days: 180 confidence: medium layer: window items: type: object properties: destination: type: string example: TR name: type: string example: Turkey slug: type: string example: turkey mode: type: string example: visa_free days: type: integer example: 90 stay: type: object properties: window: type: string example: rolling window_days: type: integer example: 180 confidence: type: string example: medium layer: type: string example: window meta: type: object properties: passport: type: string example: DE total: type: integer example: 199 by_mode: type: object properties: visa_free: type: integer example: 130 tags: - 'Visa & Border Rules' security: [] parameters: - in: path name: code description: 'ISO 3166-1 alpha-2 code of the passport.' example: DE required: true schema: type: string '/api/visa/map/{code}': get: summary: 'Compact payload for colouring a world map by one passport.' operationId: compactPayloadForColouringAWorldMapByOnePassport description: "Same data as /passport/{code} stripped to what a choropleth needs:\n`m` — entry mode, `d` — visa-free days if known." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: 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 properties: success: type: boolean example: true data: type: object properties: TR: type: object properties: m: type: string example: visa_free d: type: integer example: 90 RU: type: object properties: m: type: string example: visa_required d: type: string example: null nullable: true meta: type: object properties: passport: type: string example: US legend: type: array example: - visa_free - voa - eta - e_visa - visa_required - no_admission - self items: type: string tags: - 'Visa & Border Rules' security: [] parameters: - in: path name: code description: 'ISO 3166-1 alpha-2 code of the passport.' example: US required: true schema: type: string '/api/visa/vehicle/{place}': get: summary: 'Temporary vehicle import rules for a country.' operationId: temporaryVehicleImportRulesForACountry description: "Only rules we can stand behind are returned: an official source, or two\nindependent research runs agreeing, or manual verification. A country\nwith nothing trustworthy returns an empty list rather than a guess —\nthe cost of being wrong here is a vehicle held at the border." parameters: - in: query name: locale description: 'Language of the place name. Defaults to en.' example: en required: false schema: type: string description: 'Language of the place name. Defaults to en.' example: en responses: 200: description: '' content: application/json: schema: type: object example: 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 properties: success: type: boolean example: true data: type: array example: - 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 items: type: object properties: weight_class: type: string example: le35 plate_group: type: string example: null nullable: true max_days: type: integer example: 90 basis: type: string example: per_entry window_days: type: string example: null nullable: true carnet_required: type: boolean example: false extension_possible: type: string example: null nullable: true green_card: type: string example: border_insurance confidence: type: string example: high source_url: type: string example: 'https://georgiacb.com/en/articles/customs-procedure-temporary-importation-admission-im-53' curated: type: boolean example: true meta: type: object properties: place: type: string example: GE name: type: string example: Georgia green_card_by_plate: type: object properties: eu: type: string example: plate_ok tags: - 'Visa & Border Rules' security: [] parameters: - in: path name: place description: 'ISO alpha-2 code, slug or zone code.' example: georgia required: true schema: type: string