# Vietnam Transit Scraper - VNR Trains & Intercity Bus (`jungle_synthesizer/vietnam-transit-scraper`) Actor

Vietnam transit via Vexere: Vietnam Railways (Reunification Express, Hà Nội-Sa Pa sleeper) with train numbers, seat-class fares in VND, bilingual VI/EN station names, plus intercity buses with sleeper-bed/cabin types and pickup/dropoff points.

- **URL**: https://apify.com/jungle\_synthesizer/vietnam-transit-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Travel, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Vietnam Transit Scraper — VNR Trains & Intercity Bus

Scrape Vietnam transit data from the [Vexere aggregator](https://vexere.com/), the largest Vietnamese ticket platform. Returns Vietnam Railways (VNR) train schedules — including the Reunification Express Hà Nội ↔ HCMC and the Hà Nội ↔ Sa Pa sleeper — alongside intercity bus services across major operators, with bilingual Vietnamese / English station names and fares in Vietnamese đồng.

---

### Vietnam Transit Scraper Features

- Returns Vietnam Railways (VNR) services with train numbers (SE1, SE3, SE5, SNT2, ...) and seat-class information.
- Surfaces intercity buses across major Vietnamese carriers (Phương Trang/Futa, Hoàng Long, The Sinh Tourist, Mai Linh) with bus-type detail — Sleeper Bed, Sleeper Cabin, Seat 45, Limousine 9.
- Three modes — `daily_summary` for aggregate counts and fare ranges, `train_search` for per-train listings, `bus_search` for per-trip listings. Pick what you need, skip what you don't.
- Bilingual fields: every station carries a Vietnamese name with diacritics and an English fallback. The data isn't useful if half your team can't read it.
- Sleeper detection — flags overnight services so you can filter to the trains and cabin buses people actually book for the journey.
- Bus pickup and dropoff points include district names and lat/lon coordinates. Geocoded out of the box.
- No browser, no proxy required. Pure JSON API, fast and cheap.
- Pay-per-event pricing: $0.10 per actor start + $0.001 per record.

---

### What Can You Do With Vietnam Transit Data?

- **Travel apps & itinerary planners** — Power Hà Nội ↔ Sa Pa sleeper bookings or Reunification Express search without scraping the official VNR site, which is gated behind login plus an obfuscated payload cipher.
- **Tourism platforms** — Track inventory, fare ranges, and seat-class availability for popular backpacker corridors (Hà Nội–HCMC, Đà Nẵng–Huế, HCMC–Đà Lạt).
- **MaaS startups** — Index intercity bus operators across Vietnam in one schema. Vexere covers ~500 carriers; you'd otherwise need to scrape each operator's site.
- **Price-tracking dashboards** — Daily summary mode emits min/max/avg fares per A→B/date. Run it nightly, plot the curve.
- **SE Asia rail enthusiasts** — Pull the full SE1–SE10 + SNT timetable on any date. The dataset includes carriage types and distances.

---

### How Vietnam Transit Scraper Works

1. Pick a mode — `daily_summary`, `train_search`, or `bus_search`.
2. Provide an origin and destination by city name (English, Vietnamese, with or without diacritics) or numeric Vexere city ID. The scraper resolves Hà Nội, HCMC, Đà Nẵng, Sa Pa, Đà Lạt, Nha Trang, Huế, Hội An, and 20+ other cities out of the box.
3. The scraper hits Vexere's `internal-vroute.vexere.com` API with a static FE Bearer token and polls until inventory populates (a few seconds for fresh queries). It handles the polling for you.
4. Records flow into the dataset with a stable schema, ready for export to CSV, JSON, or Excel.

---

### Input

```json
{
  "mode": "train_search",
  "origin": "Hanoi",
  "destination": "Ho Chi Minh City",
  "date": "",
  "sleeperOnly": false,
  "maxItems": 15
}
````

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `mode` | string | `train_search` | One of `daily_summary`, `train_search`, `bus_search`. |
| `origin` | string | `Hanoi` | Origin city. English, Vietnamese with or without diacritics. |
| `destination` | string | `Ho Chi Minh City` | Destination city, same format as origin. |
| `originCityId` | integer | (none) | Override: numeric Vexere city ID. Use when the city isn't in the lookup table. |
| `destinationCityId` | integer | (none) | Override: numeric Vexere city ID. |
| `date` | string | today + 7 (ICT) | Travel date, `YYYY-MM-DD`. Empty defaults to a week out. |
| `sleeperOnly` | boolean | `false` | Filter to overnight sleeper trains and sleeper-cabin buses. |
| `maxItems` | integer | `15` | Maximum records returned. Tester runs the default; raise for production. |
| `proxyConfiguration` | object | `{ "useApifyProxy": false }` | Proxy not required. |

Bus search example (Hà Nội → Sa Pa):

```json
{
  "mode": "bus_search",
  "origin": "Hanoi",
  "destination": "Sapa",
  "maxItems": 50
}
```

Daily summary example (HCMC → Nha Trang):

```json
{
  "mode": "daily_summary",
  "origin": "Ho Chi Minh City",
  "destination": "Nha Trang",
  "date": "2026-06-15"
}
```

***

### Vietnam Transit Scraper Output Fields

#### Train search (`mode: "train_search"`)

```json
{
  "record_type": "train",
  "service_id": "VNR|SE7|2026-05-08|06:00|HNO|SGO",
  "operator": "Vietnam Railways Corporation",
  "operator_code": "VNR",
  "service_type": "rail",
  "origin_station": "Hà Nội",
  "origin_station_en": "Ha Noi",
  "origin_station_code": "HNO",
  "destination_station": "Sài Gòn",
  "destination_station_en": "Saigon",
  "destination_station_code": "SGO",
  "departure_date": "2026-05-08",
  "departure_time": "06:00",
  "arrival_date": "2026-05-09",
  "arrival_time": "17:35",
  "duration_minutes": 2495,
  "train_number": "SE7",
  "seats_available": 117,
  "distance_km": 1726,
  "is_sleeper": true,
  "route_url": "https://vexere.com/",
  "scraped_at": "2026-05-01T16:38:29.217Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `record_type` | string | `train`. |
| `service_id` | string | Vexere idIndex — `VNR\|<train>\|<date>\|<time>\|<from-code>\|<to-code>`. |
| `operator` | string | `Vietnam Railways Corporation`. |
| `operator_code` | string | `VNR`. |
| `service_type` | string | `rail`. |
| `origin_station` | string | Vietnamese name with diacritics. |
| `origin_station_en` | string | English / diacritic-stripped fallback. |
| `origin_station_code` | string | 3-letter VNR code (HNO, SGO, DNA, ...). |
| `destination_station` | string | Vietnamese destination. |
| `destination_station_en` | string | English destination. |
| `destination_station_code` | string | 3-letter VNR code. |
| `departure_date` | string | `YYYY-MM-DD` (ICT). |
| `departure_time` | string | `HH:MM` (ICT). |
| `arrival_date` | string | `YYYY-MM-DD` (ICT). |
| `arrival_time` | string | `HH:MM` (ICT). |
| `duration_minutes` | number | Total journey duration. |
| `train_number` | string | SE1, SE3, SE5, SNT2, ... |
| `seats_available` | number | Total available seats across carriages. |
| `distance_km` | number | Route distance in km. |
| `is_sleeper` | boolean | True for SE-class and SNT night trains. |
| `route_url` | string | Vexere homepage for verification. |
| `scraped_at` | string | ISO-8601 extraction timestamp. |

#### Bus search (`mode: "bus_search"`)

```json
{
  "record_type": "bus",
  "service_id": "473571045_2026-05-08_23:46_178500_178508",
  "operator": "HK BUSLINES",
  "service_type": "bus_intercity",
  "origin_station": "Văn phòng 70 Nguyễn Hữu Huân",
  "origin_station_en": "Van phong 70 Nguyen Huu Huan",
  "destination_station": "Văn phòng 732 Điện Biên Phủ",
  "destination_station_en": "Van phong 732 Dien Bien Phu",
  "departure_date": "2026-05-08",
  "departure_time": "23:46",
  "arrival_date": "2026-05-09",
  "arrival_time": "05:31",
  "duration_minutes": 345,
  "distance_km": 318,
  "bus_type": "Sleeper Cabin",
  "is_sleeper": true,
  "pickup_points": [
    "Trạm Buýt Bầu | Đông Anh | 21.12936,105.77987",
    "Sân bay Nội Bài (Ga Quốc Tế) | Sóc Sơn | 21.21702,105.79323"
  ],
  "dropoff_points": [
    "Văn phòng 732 Điện Biên Phủ | Sa Pa | 22.34064,103.84035",
    "Trả tại thị trấn Sapa | Sa Pa | 22.33831,103.83642"
  ],
  "scraped_at": "2026-05-01T16:40:29.327Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `record_type` | string | `bus`. |
| `service_id` | string | Vexere internal trip ID. |
| `operator` | string | Bus company name (Phương Trang, Hoàng Long, The Sinh Tourist, ...). |
| `service_type` | string | `bus_intercity`. |
| `bus_type` | string | `Sleeper Bed`, `Sleeper Cabin`, `Seat`, `Limousine`, ... |
| `origin_station` / `_en` | string | Pickup-area name (Vietnamese / English). |
| `destination_station` / `_en` | string | Dropoff-area name. |
| `departure_date` / `_time` | string | Scheduled departure (ICT). |
| `arrival_date` / `_time` | string | Scheduled arrival (ICT). |
| `duration_minutes` | number | Journey duration. |
| `distance_km` | number | Route distance. |
| `is_sleeper` | boolean | True for sleeper-bed and sleeper-cabin buses. |
| `pickup_points` | array | Up to 10 pickup points; each entry is `name \| district \| lat,lon`. |
| `dropoff_points` | array | Up to 10 dropoff points; same format. |
| `scraped_at` | string | ISO-8601 timestamp. |

#### Daily summary (`mode: "daily_summary"`)

```json
{
  "record_type": "daily_summary",
  "service_id": "vnr-summary-92-77-2026-05-08",
  "operator": "Vietnam Railways Corporation",
  "operator_code": "VNR",
  "service_type": "rail",
  "origin_station": "Ga Sài Gòn",
  "origin_station_en": "Sai Gon Railway Station",
  "destination_station": "Ga Nha Trang",
  "destination_station_en": "Nha Trang Railway Station",
  "departure_date": "2026-05-08",
  "departure_time": "06:00",
  "duration_minutes": 428,
  "min_fare_vnd": 403000,
  "max_fare_vnd": 1973000,
  "avg_fare_vnd": 836571,
  "distance_km": 411,
  "service_count": 7,
  "train_types_available": ["SE10", "SE2", "SE22", "SE4", "SE6", "SE8", "SNT2"],
  "seat_classes": [
    "NAM:Soft seat AC (Ngồi Mềm)",
    "NGM:Soft sleeper AC 4-berth (Nằm Giường Mềm)",
    "NAC:Hard seat (Ngồi Cứng)"
  ],
  "is_sleeper": true,
  "scraped_at": "2026-05-01T16:38:51.812Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `record_type` | string | `daily_summary`. |
| `service_count` | number | Number of trains running on the date. |
| `min_fare_vnd` / `max_fare_vnd` / `avg_fare_vnd` | number | Daily fare range and mean in VND. |
| `train_types_available` | array | Train numbers running that day. |
| `seat_classes` | array | Available carriage codes with bilingual labels. |
| `duration_minutes` | number | Aggregate route duration. |
| `distance_km` | number | Route distance. |

***

### FAQ

#### How do I scrape Vietnam Railways train schedules?

Vietnam Transit Scraper hits Vexere's aggregator API, which republishes the official VNR (`dsvn.vn`) inventory. The official site requires login plus a custom encryption layer for search; Vexere is the cleaner path. Set `mode: "train_search"`, pick origin and destination, and you get train numbers, times, durations, and seat counts.

#### Does this scraper need a proxy?

Vietnam Transit Scraper does not need a proxy. Vexere is publicly reachable from anywhere; the static FE Bearer token authenticates the call. If you opt in via `proxyConfiguration` for high-volume runs, the scraper handles the LIMITED\_PERMISSIONS proxy flow correctly.

#### How much does it cost to run?

Vietnam Transit Scraper costs $0.10 per actor start + $0.001 per record. A typical Hà Nội → HCMC train search returns 5–10 records, so a single run is well under a cent of record cost. Bus searches on popular corridors return 30–100+ records, still in the fraction-of-a-dollar range.

#### Can I search by Vietnamese station names with diacritics?

Vietnam Transit Scraper resolves `Hà Nội`, `Đà Nẵng`, `Hồ Chí Minh`, `Sài Gòn`, `Sa Pa`, and similar Vietnamese forms with or without tone marks. The English fallback works too — `Hanoi`, `Da Nang`, `HCMC`, `Saigon`, `Sapa`. If you need a city not in the built-in lookup, pass the numeric Vexere ID via `originCityId` / `destinationCityId`.

#### What's the difference between the three modes?

`daily_summary` returns one aggregate record per A→B/date — fare range, train types, count. Fast and lightweight. `train_search` returns one record per running train, with departure times and seat availability. `bus_search` does the same for intercity buses, plus pickup/dropoff geocodes. Pick `train_search` for booking-class detail; pick `daily_summary` for price-tracking dashboards.

***

### Need More Features?

Need additional fields, bus operators, or a different target site? File an issue or get in touch.

### Why Use Vietnam Transit Scraper?

- **No bot war required** — Vexere ships a static client-side Bearer token; we capture once and replay. No CAPTCHAs, no proxy gymnastics.
- **Bilingual data out of the box** — every station carries a Vietnamese name with diacritics and an English fallback. The data is usable downstream without a second extraction pass.
- **Cheaper than building it yourself** — $0.001 per record on Apify's pay-per-event pricing beats the time cost of reverse-engineering `dsvn.vn`'s payload cipher and OAuth dance.

# Actor input Schema

## `sp_intended_usage` (type: `string`):

Please describe how you plan to use the data extracted by this crawler.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

Provide your email address so we can get in touch with you.

## `mode` (type: `string`):

What to extract. daily\_summary returns one aggregate record per A→B/date (count, fare range, train types). train\_search returns one record per train service. bus\_search returns one record per intercity bus trip.

## `origin` (type: `string`):

Origin city. Accepts English (Hanoi, Ho Chi Minh City, Da Nang, Sapa) or Vietnamese with or without diacritics (Hà Nội, Sài Gòn, Đà Nẵng, Sa Pa). Use originCityId to override.

## `destination` (type: `string`):

Destination city. Same format as Origin.

## `originCityId` (type: `integer`):

Vexere numeric city ID. Overrides Origin name lookup. Useful for cities not in the built-in lookup table. Examples: 24=Hanoi, 29=HCMC, 15=Da Nang, 482=Sa Pa.

## `destinationCityId` (type: `integer`):

Vexere numeric city ID. Overrides Destination name lookup.

## `date` (type: `string`):

Travel date. Leave empty to use today (Vietnam ICT timezone).

## `sleeperOnly` (type: `boolean`):

Filter results to overnight sleeper services only. Trains: keeps records where train\_number indicates sleeper (SE class trains and night services). Buses: keeps sleeper / sleeper-cabin bus types only.

## `maxItems` (type: `integer`):

Maximum records to return. The Apify automated tester runs the default — keep small for fast validation. Set higher for production runs.

## `proxyConfiguration` (type: `object`):

Proxy not required — Vexere is publicly reachable. Default: no proxy.

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "mode": "train_search",
  "origin": "Hanoi",
  "destination": "Ho Chi Minh City",
  "sleeperOnly": false,
  "maxItems": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "mode": "train_search",
    "origin": "Hanoi",
    "destination": "Ho Chi Minh City",
    "date": "",
    "sleeperOnly": false,
    "maxItems": 15,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/vietnam-transit-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "mode": "train_search",
    "origin": "Hanoi",
    "destination": "Ho Chi Minh City",
    "date": "",
    "sleeperOnly": False,
    "maxItems": 15,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/vietnam-transit-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "mode": "train_search",
  "origin": "Hanoi",
  "destination": "Ho Chi Minh City",
  "date": "",
  "sleeperOnly": false,
  "maxItems": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call jungle_synthesizer/vietnam-transit-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=jungle_synthesizer/vietnam-transit-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Vietnam Transit Scraper - VNR Trains & Intercity Bus",
        "description": "Vietnam transit via Vexere: Vietnam Railways (Reunification Express, Hà Nội-Sa Pa sleeper) with train numbers, seat-class fares in VND, bilingual VI/EN station names, plus intercity buses with sleeper-bed/cabin types and pickup/dropoff points.",
        "version": "1.0",
        "x-build-id": "ilrrBySc6rQBwCzUL"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/jungle_synthesizer~vietnam-transit-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-jungle_synthesizer-vietnam-transit-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/jungle_synthesizer~vietnam-transit-scraper/runs": {
            "post": {
                "operationId": "runs-sync-jungle_synthesizer-vietnam-transit-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/jungle_synthesizer~vietnam-transit-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-jungle_synthesizer-vietnam-transit-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "sp_intended_usage": {
                        "title": "What is the intended usage of this data?",
                        "minLength": 1,
                        "type": "string",
                        "description": "Please describe how you plan to use the data extracted by this crawler."
                    },
                    "sp_improvement_suggestions": {
                        "title": "How can we improve this crawler for you?",
                        "minLength": 1,
                        "type": "string",
                        "description": "Provide any feedback or suggestions for improvements."
                    },
                    "sp_contact": {
                        "title": "Contact Email",
                        "minLength": 1,
                        "type": "string",
                        "description": "Provide your email address so we can get in touch with you."
                    },
                    "mode": {
                        "title": "Scrape Mode",
                        "enum": [
                            "daily_summary",
                            "train_search",
                            "bus_search"
                        ],
                        "type": "string",
                        "description": "What to extract. daily_summary returns one aggregate record per A→B/date (count, fare range, train types). train_search returns one record per train service. bus_search returns one record per intercity bus trip.",
                        "default": "train_search"
                    },
                    "origin": {
                        "title": "Origin City",
                        "type": "string",
                        "description": "Origin city. Accepts English (Hanoi, Ho Chi Minh City, Da Nang, Sapa) or Vietnamese with or without diacritics (Hà Nội, Sài Gòn, Đà Nẵng, Sa Pa). Use originCityId to override."
                    },
                    "destination": {
                        "title": "Destination City",
                        "type": "string",
                        "description": "Destination city. Same format as Origin."
                    },
                    "originCityId": {
                        "title": "Origin City ID (override)",
                        "type": "integer",
                        "description": "Vexere numeric city ID. Overrides Origin name lookup. Useful for cities not in the built-in lookup table. Examples: 24=Hanoi, 29=HCMC, 15=Da Nang, 482=Sa Pa."
                    },
                    "destinationCityId": {
                        "title": "Destination City ID (override)",
                        "type": "integer",
                        "description": "Vexere numeric city ID. Overrides Destination name lookup."
                    },
                    "date": {
                        "title": "Date (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Travel date. Leave empty to use today (Vietnam ICT timezone)."
                    },
                    "sleeperOnly": {
                        "title": "Sleeper Services Only",
                        "type": "boolean",
                        "description": "Filter results to overnight sleeper services only. Trains: keeps records where train_number indicates sleeper (SE class trains and night services). Buses: keeps sleeper / sleeper-cabin bus types only.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Max Items",
                        "type": "integer",
                        "description": "Maximum records to return. The Apify automated tester runs the default — keep small for fast validation. Set higher for production runs.",
                        "default": 15
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy not required — Vexere is publicly reachable. Default: no proxy."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
