Build a same-train berth chain when no berth covers the full route.
GET /v1/charts/vacant-berths/hopping
Scope charts:read · Credits 10 · Plans Scale and Enterprise
Combines chart data, schedule, coach position, preferences, optional fares, alternate boarding, and multiple optimization strategies.
Send your key in the X-RailCore-Key header. This operation requires the charts:read scope. See the authentication guide.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
train_number | query | string | Required | Train number, 4 to 6 uppercase letters or digits. |
from | query | string | Required | Boarding station code. |
to | query | string | Required | Destination station code. |
date | query | string(date) | Required | Journey date in YYYY-MM-DD format. |
via | query | string | Optional | Pinned intermediate station codes in journey order, comma-separated. |
max_hops | query | integer | Optional | Maximum hopping chain length. |
prefer_berth | query | string | Optional | Preferred berth codes or aliases, comma-separated. |
avoid_berth | query | string | Optional | Berth codes or aliases to avoid. Avoid wins on conflicts. |
prefer_class | query | string | Optional | Preferred travel classes, comma-separated. |
avoid_class | query | string | Optional | Classes to skip entirely, comma-separated. |
include_fare | query | boolean | Optional | Add hop and direct-option fare data. |
include_alternate_boarding | query | boolean | Optional | Evaluate nearby stations as alternate boarding points. |
strategies | query | string | Optional | min_hops, min_seat_changes, cheapest, or all. |
alternate_boarding_mode | query | string | Optional | lightweight or extended candidate evaluation. |
alternate_boarding_max_candidates | query | integer | Optional | Maximum extended-mode candidates. |
include_cross_class | query | boolean | Optional | Build one plan that can switch classes between hops. |
Base URL https://ir.railcore.tech/v1. Keep the key in an environment variable and call from a trusted server-side environment.
curl -sS -X GET \
-H "X-RailCore-Key: $RAILCORE_KEY" \
"https://ir.railcore.tech/v1/charts/vacant-berths/hopping?train_number=12656&from=BSL&to=ADI&date=2026-08-27&via=JL%2CAN&max_hops=6&prefer_berth=LB%2CSLB&avoid_berth=UB%2CSUB&prefer_class=SL%2C3A&avoid_class=1A&include_fare=false&include_alternate_boarding=false&strategies=min_hops%2Ccheapest&alternate_boarding_mode=lightweight&alternate_boarding_max_candidates=3&include_cross_class=false"
const response = await fetch("https://ir.railcore.tech/v1/charts/vacant-berths/hopping?train_number=12656&from=BSL&to=ADI&date=2026-08-27&via=JL%2CAN&max_hops=6&prefer_berth=LB%2CSLB&avoid_berth=UB%2CSUB&prefer_class=SL%2C3A&avoid_class=1A&include_fare=false&include_alternate_boarding=false&strategies=min_hops%2Ccheapest&alternate_boarding_mode=lightweight&alternate_boarding_max_candidates=3&include_cross_class=false", {
method: "GET",
headers: {
"X-RailCore-Key": process.env.RAILCORE_KEY,
},
});
const body = await response.json();
console.log(response.status, body);
import os
import requests
response = requests.request(
"GET",
"https://ir.railcore.tech/v1/charts/vacant-berths/hopping?train_number=12656&from=BSL&to=ADI&date=2026-08-27&via=JL%2CAN&max_hops=6&prefer_berth=LB%2CSLB&avoid_berth=UB%2CSUB&prefer_class=SL%2C3A&avoid_class=1A&include_fare=false&include_alternate_boarding=false&strategies=min_hops%2Ccheapest&alternate_boarding_mode=lightweight&alternate_boarding_max_candidates=3&include_cross_class=false",
headers={"X-RailCore-Key": os.environ["RAILCORE_KEY"]},
timeout=20,
)
print(response.status_code, response.json())
This call costs 10 credits and is available on Scale and Enterprise. Per-minute and daily budgets, and the headers reporting remaining quota, are documented in rate limits and credits and billing.
| Field | Type | Description |
|---|---|---|
train_number / train_name | string | Resolved train identity. |
from_station_code / to_station_code | string | Requested segment. |
train_start_date | string(date) | Train origin start date used for chart lookup. |
remote_station_code | string | Remote charting station. |
chart_status | object | Chart one and chart two flags and preparation times. |
coach_summary[] | object[] | Coach, class, engine position, and vacant berth count. |
vacant_berths[] | object[] | Coach, class, berth, vacancy segment, split number, and segment coverage flag. |
requested_segment | object | Resolved stop sequences, stations, and pinned via points. |
direct.available | boolean | True when one berth covers the full segment. |
direct.options[] | object[] | Direct options grouped by class, with berths and optional fare. |
hopping.disabled / disabled_reason | boolean / string | null | Whether schedule limitations prevented hopping analysis. |
hopping.options[] | object[] | Per-class coverage plan, hop count, physical seat changes, reason, fare, and strategy plans. |
hopping.options[].hops[] | object[] | Effective segment, coach, class, berth, stop sequence, fare, and ergonomics for each leg. |
alternate_boarding | object | Candidate stations, vacancy deltas, chart status, fares, notes, and recommendation scores. |
cross_class | object | Optional plan that allows class changes between hops. |
_meta | object | Chart type, classes, partial failures, enrichment status, preferences, and algorithm notes. |
{
"success": true,
"data": {
"train_number": "12656",
"train_name": "Navjeevan SF Express",
"from_station_code": "BSL",
"to_station_code": "ADI",
"train_start_date": "2026-08-27",
"chart_status": {
"chart_one_prepared": true,
"chart_two_prepared": true
},
"direct": {
"available": false,
"options": []
},
"hopping": {
"disabled": false,
"disabled_reason": null,
"options": [
{
"class_code": "3A",
"is_covered": true,
"total_hops": 2,
"physical_seat_changes": 1,
"total_fare_inr": 1190,
"hops": [
{
"from_station_code": "BSL",
"to_station_code": "AN",
"coach_name": "B1",
"class_code": "3A",
"berth_number": 17,
"berth_code": "L",
"fare_inr": 610
},
{
"from_station_code": "AN",
"to_station_code": "ADI",
"coach_name": "B2",
"class_code": "3A",
"berth_number": 28,
"berth_code": "SL",
"fare_inr": 580
}
]
}
]
},
"alternate_boarding": {
"enabled": false,
"candidates": []
},
"cross_class": {
"enabled": false,
"plan": null
},
"_meta": {
"classes_requested": [
"3A"
],
"max_hops": 6,
"partial_failures": []
}
},
"meta": {
"api_version": "v1",
"request_id": "req_01J5Z7Y8N2K4M6P8R0T2V4X6Z8",
"trace_id": "trc_01J5Z7Y8N2K4M6P8R0T2V4X6Z9",
"timestamp": "2026-08-20T17:12:23.305Z",
"freshness": {
"mode": "live",
"retrieved_at": "2026-08-20T17:12:23.305Z",
"sources": [
{
"confidence": "high"
}
]
}
}
}
| Status | Code | Description | Retry |
|---|---|---|---|
| 409 | CHART_NOT_PREPARED | The chart is not ready for analysis. | Retryable |
| 400 | VALIDATION_ERROR | A required field is missing or invalid. | Not retryable |
| 401 | MISSING_API_KEY / INVALID_API_KEY | The credential is absent, unknown, disabled, or expired. | Not retryable |
| 403 | SCOPE_MISSING / PLAN_ENDPOINT_DISABLED | The key lacks the required scope or plan entitlement. | Not retryable |
| 402 | CREDITS_EXHAUSTED | The account balance cannot cover this operation. | Not retryable |
| 429 | RATE_LIMITED | Minute or daily request budget is exhausted. Honor Retry-After. | Retryable |
| 410 | API_VERSION_SUNSET | This API version has reached its announced sunset date. Migrate to a supported major version. | Not retryable |
| 502 | UPSTREAM_UNAVAILABLE | Live data could not be retrieved. Retry with backoff. | Retryable |
| 504 | UPSTREAM_TIMEOUT | The live-data request exceeded its deadline. Retry with backoff. | Retryable |
| 503 | METERING_UNAVAILABLE | Credit settlement is temporarily unavailable and no data was returned. | Retryable |
All RailCore Indian Railways API endpoints · Quickstart · Rate limits