Skip to main content

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)

Source distribution for rzd-api 3.1.0
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)

Table of built distributions (wheels) for rzd-api 3.1.0
File Interpreter ABI Platform Actions
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 log

Release 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 log

Security 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.

Select from 2 files

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 log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page