RZD API
Типизированный Python-клиент и MCP-сервер для неофициального API
ticket.rzd.ru. Проект не связан с ОАО «РЖД»; внутренние
endpoint и схема ответов могут изменяться без предупреждения.
Проверка TLS-сертификата и имени сервера включена. Для своей доверенной цепочки
используйте Config(ca_bundle="/path/to/ca-bundle.pem") или RZD_CA_BUNDLE.
Возможности
- поиск прямых поездов в одну сторону и туда-обратно;
- поиск станций по названию и синонимам;
- календарь доступности и минимальные цены по датам;
- информация о вагонах, местах, схемах, изображениях и станциях маршрута;
- dataclass-модели с полным исходным объектом в
raw; - MCP через
stdioи защищённыйstreamable-http; - retries, раздельные таймауты и кэш поиска станций.
Требуется Python 3.10–3.14.
Установка
pip install rzd-api
С MCP-сервером:
pip install "rzd-api[mcp]"
Python API
from datetime import date, timedelta
from rzd_api import RoundTripResult, RzdClient
departure = date.today() + timedelta(days=14)
return_date = departure + timedelta(days=3)
with RzdClient() as client:
result = client.search_tickets(
"Москва",
"Санкт-Петербург",
departure,
return_date=return_date,
adults=1,
children=0,
)
if isinstance(result, RoundTripResult):
for train in result.forward:
print(train.number, train.departure_time, train.min_price)
for train in result.back:
print(train.number, train.departure_time, train.min_price)
Все модели поддерживают to_dict(). Исходные узлы ответов сохраняются в raw;
у составного RoundTripSearchResult они находятся в forward.raw и back.raw.
Методы RzdClient
| Метод | Результат |
|---|---|
search_tickets(...) |
list[TrainRoute] или RoundTripResult |
search_tickets_detailed(...) |
TrainSearchResult или RoundTripSearchResult |
find_stations(query, ...) |
list[Station] |
resolve_station_code(station) |
код станции |
get_carriages(...) |
CarriageResult |
get_train_availability(...) |
TrainAvailabilityResult |
get_minimal_prices(...) |
MinimalPricingResult |
get_car_scheme(...) |
CarScheme |
get_car_images(...) |
CarImagesResult |
get_route_stations(...) |
RouteStationsResult |
get_carriages() использует актуальный CarPricing и сразу возвращает все вагоны
поезда. car_number этому методу больше не передаётся. Значения number,
car_sub_type, service_class, carrier и numeration из выбранного Carriage
можно передать в get_car_scheme() и get_car_images().
with RzdClient() as client:
carriages = client.get_carriages(
"2001025", "2004001", departure, "00:48", "059Г"
)
car = carriages.cars[0]
scheme = client.get_car_scheme(
departure,
"00:48",
car.train_number or "059Г",
car.number or "",
car.car_sub_type or "",
car.service_class or "",
car.carrier or "",
car_numeration=car.numeration or "FromHead",
)
only_with_seats=True фильтрует по доступности мест из CarGroups. Современный
pricing endpoint не поддерживает маршруты с пересадками и фильтр типа транспорта,
поэтому include_transfers=True и transport_type="trains"|"suburban" явно
возвращают NotImplementedError.
search_tickets_detailed() принимает те же параметры, но сохраняет метаданные
направления: trains, partial (NotAllTrainsReturned), moscow_time и raw.
partial=None означает, что источник не сообщил о полноте. Для туда-обратно
forward и back содержат отдельные TrainSearchResult. Фильтрация мест не
меняет исходный raw и не превращает неполный ответ в полный.
У TrainRoute явно разделены local_departure_time/local_arrival_time и
moscow_departure_time/moscow_arrival_time. Старые departure_time и
arrival_time сохраняют приоритет московского времени из версии 3.0;
для показа местного времени используйте новые поля.
get_route_stations() возвращает все варианты в routes: list[RouteVariant].
Старые stations, train_number и названия относятся к первому варианту:
остановки разных маршрутов больше не склеиваются. Необязательный
actual_movement допускает boolean, 0/1 и строки true/false; неизвестное
значение становится None и сохраняется в raw. Остальные ошибки схемы
продолжают вызывать RzdSchemaError.
Поиск станций поддерживает категории city/train, а также ISDK-формат
transport_node_suggests с Codes.Railway, CityId, Timezone и Stations.
Узлы разных вокзалов с одинаковым кодом сохраняются отдельно. Узлы без
железнодорожного кода не подставляются в поиск поездов. По умолчанию используется
прежний /api/v1/suggests; для ISDK задайте
Config(station_search_url="https://ticket.rzd.ru/isdk/suggests").
Конфигурация
from rzd_api import Config, RzdClient
config = Config(
language="ru",
# По умолчанию выводится из base_url.
b2b_base_url=None,
connect_timeout=5,
read_timeout=20,
retry_total=3,
retry_backoff=0.5,
station_cache_ttl=3600,
station_cache_size=256,
proxy=None,
ca_bundle=None, # Или RZD_CA_BUNDLE; проверка TLS всегда включена.
station_search_url=None,
)
client = RzdClient(config)
Ошибки наследуются от RzdError: validation, transport, HTTP, API, schema,
station-not-found и ambiguous-station.
TLS и доверенные сертификаты
При CERTIFICATE_VERIFY_FAILED настройте доверенную цепочку для своей среды.
Корневой сертификат российского НУЦ следует получать с
официальной страницы Госуслуг, проверяя источник
и отпечаток. Библиотека не скачивает сертификаты и не меняет системное хранилище.
ca_bundle — путь к PEM bundle с необходимыми доверенными CA; явно заданный
путь имеет приоритет над RZD_CA_BUNDLE и REQUESTS_CA_BUNDLE.
Без него используются стандартные настройки доверия Requests.
Для MCP переменная RZD_CA_BUNDLE действует на все tools. В Docker смонтируйте
файл только для чтения и передайте путь внутри контейнера:
docker run --rm -i \
--mount type=bind,src=/absolute/path/ca-bundle.pem,dst=/run/rzd-ca.pem,readonly \
-e RZD_CA_BUNDLE=/run/rzd-ca.pem \
-e MCP_TRANSPORT=stdio rzd-api:3.1.0
TLS/HTTP/transport errors остаются исключениями, а не пустым результатом поиска.
MCP
Инструменты: search_tickets, find_stations, get_carriages,
get_train_availability, get_minimal_prices, get_car_scheme,
get_car_images, get_route_stations.
Все tools по умолчанию исключают raw на всех уровнях ответа. Передайте
include_raw=true, если нужны исходные поля РЖД. Python-модели и их to_dict()
сохраняют полный raw. Списки не обрезаются молча.
У search_tickets флаг include_metadata=true возвращает подробный результат
с partial и серверным временем; без него сохраняется прежняя форма списка
или пары направлений. Для оценки полноты выдачи используйте этот флаг.
Локальный stdio:
rzd-mcp-server
Streamable HTTP на loopback без токена:
MCP_TRANSPORT=streamable-http MCP_HOST=127.0.0.1 rzd-mcp-server
При привязке к non-loopback адресу требуется Bearer-токен минимум из 32 символов:
export MCP_AUTH_TOKEN="replace-with-a-random-token-at-least-32-characters"
MCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 rzd-mcp-server
Endpoint MCP: http://localhost:8000/mcp; healthcheck: /health. Лимит по
умолчанию — 60 запросов в минуту, настраивается через
MCP_RATE_LIMIT_PER_MINUTE. Допустимые Host headers можно перечислить через
MCP_ALLOWED_HOSTS.
Docker
export MCP_AUTH_TOKEN="replace-with-a-random-token-at-least-32-characters"
docker compose up -d
curl http://127.0.0.1:8000/health
Контейнер запускается от UID 10001, без Linux capabilities, и публикует порт только на loopback хоста.
Разработка
python -m pip install -e ".[dev]"
make check
Live smoke test является opt-in:
RZD_LIVE_TEST=1 pytest tests/integration -m integration -v
Для живого API нужен сетевой выход с доступом к РЖД и настроенный CA bundle.
Live-тесты не повторяют запросы автоматически. RZD_LIVE_PROXY задаёт proxy
только для этих тестов. Еженедельный GitHub live smoke включается переменной
репозитория RZD_LIVE_ENABLED=true после настройки доступа; без неё расписание
пропускается. RZD_LIVE_RUNNER позволяет выбрать подходящий runner, секрет
RZD_LIVE_PROXY — proxy. Ручной запуск доступен независимо от расписания.
Workflow получает CA с официального HTTPS-источника и проверяет закреплённый
SHA-256 отпечаток; при ротации сертификата проверка завершится ошибкой.
Offline CI запускается независимо от наличия сетевого доступа к РЖД.
Переход с 1.x описан в MIGRATION.md, изменения релизов — в CHANGELOG.md.
Лицензия
MIT
Происхождение заимствований и благодарности авторам — в CREDITS.md.
Metadata
Release files for rzd-api 3.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| rzd_api-3.1.0.tar.gz | 44.4 kB | With provenance | Details for rzd_api-3.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| rzd_api-3.1.0-py3-none-any.whl | Python 3 | none | any | Details for rzd_api-3.1.0-py3-none-any.whl |
Total release size: 73.9 kB
Release files / rzd_api-3.1.0.tar.gz
| Download URL | rzd_api-3.1.0.tar.gz |
|---|---|
| Size | 44.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2135b69880e16d45f66ebf7d3381920230e939e84ee7496bc15dfae5c5aa16f5
|
|
BLAKE2b-256 checksum How to use checksums |
f2e3babe1f1272f7d417434da92c954fa1e260b86a28472ad667314122ad5b76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logRelease files / rzd_api-3.1.0-py3-none-any.whl
| Download URL | rzd_api-3.1.0-py3-none-any.whl |
|---|---|
| Size | 29.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7efa02a3ecbde9c22680980de3f4eca333db866a3409db2d8e7c88ce50556695
|
|
BLAKE2b-256 checksum How to use checksums |
ee320831ea6a707773096697807ac4dc8e0500e6b21d41999ba02cb437f8daaf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logSecurity for rzd-api 3.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for rzd_api-3.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.