Skip to content

API Reference

Justintunsday edited this page Sep 14, 2026 · 2 revisions

API 参考

  • 基础地址(自部署时替换为你的域名):https://ts-api.tundrey.com
  • 全部端点为 GET,返回 JSON(UTF-8)
  • 端点索引:GET /GET /v1
  • 时间均为北京时间;距离单位米;时长单位秒

通用约定

认证(可选)

默认关闭。若部署时设置了 API_KEY 环境变量,所有 /v1/* 请求需携带以下任意一种凭证:

方式 示例
请求头 X-API-Key curl -H "X-API-Key: <key>" ...
Bearer Token curl -H "Authorization: Bearer <key>" ...
查询参数 curl "...?key=<key>"

错误格式

{
  "error": {
    "code": "invalid_params",
    "message": "One or more request parameters are invalid.",
    "details": [{ "param": "lat", "message": "must be a decimal number, e.g. '31.230416'" }]
  }
}
HTTP code 说明
400 invalid_params 参数缺失、格式错误、越界
401 unauthorized 已启用 API Key 但未提供 / 不正确
403 origin_not_allowed 来源不在 CORS 白名单
404 not_found 路径不存在
405 method_not_allowed 使用了非 GET/HEAD/OPTIONS 方法
429 rate_limited 触发限流(响应带 Retry-After: 60
502 upstream_error 上游返回异常或响应无法解析
504 upstream_timeout 上游超时(默认 15s)

CORS 与限流

  • 默认 Access-Control-Allow-Origin: *,可直接在浏览器前端调用。
  • 服务端可选按 IP 限流(部署时设置 RATE_LIMIT_PER_MINUTE)。

缓存

端点 Cache-Control
/v1/cities public, max-age=3600live=trueno-store
/v1/cities/config public, max-age=600
/v1/reverse-geocode public, max-age=86400
/v1/lines/route public, max-age=86400
/v1/lines/timetable public, max-age=3600
实时类端点 no-store

坐标系(WGS-84 / GCJ-02)与字段含义见 Coordinates-and-Fields


基础信息

GET /v1/health

存活探针,无参数。

{
  "status": "ok",
  "name": "chelaile-api",
  "version": "2.0.0",
  "time": "2026-09-14T11:00:00.000Z",
  "uptimeSeconds": 42
}

GET /v1/cities

支持的城市列表。默认读静态数据集(GitHub/jsDelivr 或本地文件),不占用上游配额。

参数 类型 默认 说明
hot_only boolean true 只返回热门城市(12 个);false 返回全部 480 个
live boolean false true 时忽略数据集直接回源上游

boolean 参数接受 true/false1/0

{
  "origin": "github",
  "updatedAt": "2026-09-14T08:54:05.173Z",
  "hotOnly": true,
  "count": 12,
  "total": 480,
  "cities": [
    { "cityId": "034", "cityName": "上海", "pinyin": "ShangHai", "supportSubway": true, "hot": true }
  ]
}

origin 取值:github(CDN/仓库)、file(本地文件)、upstream(实时上游)。

GET /v1/cities/config

参数 类型 必填 说明
city_id string 城市 ID,如 034
{
  "maxInterval": 30,
  "arrivingStationLimitSeconds": 180,
  "busDisplayConfig": { "lineDetail": "time#order#distance", "other": "time#order" }
}

地理与定位

GET /v1/reverse-geocode

WGS-84 经纬度 → 中文地址。

参数 类型 必填 说明
lat number string WGS-84 纬度
lng number string WGS-84 经度
{
  "formatted": "上海市黄浦区南京东路街道延安高架路凯迪拉克·上海音乐厅",
  "province": "上海市",
  "city": "上海市",
  "district": "黄浦区",
  "township": "南京东路街道",
  "citycode": "021",
  "adcode": "310101"
}

GET /v1/my-location

按 IP 估算位置,精度城市级(约 10 km)。

参数 类型 必填 说明
ip string 指定 IP;省略时使用服务器出口 IP,部署在大陆的服务器更准确
{
  "lat": 31.2222, "lng": 121.4581, "gpsType": "wgs",
  "city": "上海", "region": "上海市", "country": "中国",
  "ip": "116.236.0.1", "isp": "China Telecom",
  "precision": "city-level (~10 km); not suitable for stop-level queries",
  "inChina": true
}

境外 IP 会返回 inChina: false 并附带 warning


搜索

GET /v1/search

参数 类型 必填 说明
city_id string 城市 ID
keyword string 关键词,如 7171路地铁2号线陆家嘴
{
  "highlightKey": "71",
  "lines": [
    {
      "name": "71", "lineNo": "r95817", "isSubway": false,
      "directions": [
        { "direction": 0, "lineId": "21283603183", "startSn": "延安东路外滩", "endSn": "申昆路枢纽站" },
        { "direction": 1, "lineId": "21283603182", "startSn": "申昆路枢纽站", "endSn": "延安东路外滩" }
      ],
      "lineId": "21283603183", "direction": 0, "startSn": "延安东路外滩", "endSn": "申昆路枢纽站"
    }
  ],
  "stations": [
    {
      "sId": "021-15232", "sn": "西藏中路",
      "lat": 31.231006, "lng": 121.474316, "gpsType": "wgs",
      "physicalStId": "2868ecd4156f42b4b4cd38bfbd5dcb00",
      "namesakeStId": "c2bd23ef55aa0701976b156087099c9c",
      "isSubway": false
    }
  ],
  "pois": [
    { "name": "71路", "address": "中山东一路", "tag": "公交线路", "district": "黄浦区", "lat": 31.233021, "lng": 121.49073, "gpsType": "gcj" }
  ]
}

要点:

  • 同线路上下行折叠进 directions[];顶层 lineId/direction/startSn/endSn 是 direction=0 的兼容字段。
  • stations[].lat/lng 为 WGS-84;pois[].lat/lng 为 GCJ-02。
  • isSubway: true 的线路不支持 /v1/lines/detail(返回 empty: true),改用 /v1/stops/detail/v1/transit/plan

GET /v1/search/more

/v1/search 同参,另加:

参数 类型 默认 说明
type "1" | "2" | "3" "1" 1 更多线路、2 更多站点、3 更多 POI

站点

GET /v1/stops/nearby

参数 类型 必填 默认 说明
city_id string 城市 ID
lat / lng number string WGS-84 坐标
limit integer 5 返回最近站点数,1–20
{
  "stops": [
    {
      "sId": "021-15232", "sn": "西藏中路", "distance": 87, "isSubway": false,
      "physicalStId": "2868ecd4156f42b4b4cd38bfbd5dcb00",
      "namesakeStId": "c2bd23ef55aa0701976b156087099c9c",
      "lines": [
        {
          "lineId": "21283603183", "name": "71", "direction": 0, "endSn": "申昆路枢纽站",
          "status": "", "targetOrder": 2, "targetStationId": "021-15232",
          "buses": [
            { "busId": "021-15232-1", "order": 2, "arrivalTime": 1779070466055, "travelTime": 90, "distanceToDest": 881, "capacity": 0 }
          ]
        }
      ],
      "subwayLines": []
    }
  ]
}

lines[].lineId + lines[].targetOrder + lines[].targetStationId 可直接用于 /v1/lines/realtime

GET /v1/stops/detail

参数 类型 必填 说明
city_id string 城市 ID
physical_st_id string 来自 /v1/stops/nearby/v1/search
namesake_st_id string 建议携带,来自同一来源
first_line_id string 高亮某条线路
lat / lng number string 传入后返回 distance
{
  "stations": [
    {
      "sId": "021-15232", "sn": "西藏中路", "lat": 31.231006, "lng": 121.474316,
      "lines": [
        {
          "lineId": "21283603183", "name": "71", "direction": 0,
          "startSn": "延安东路外滩", "endSn": "申昆路枢纽站",
          "firstTime": "05:30", "lastTime": "23:30", "price": "2元",
          "targetOrder": 2, "buses": []
        }
      ],
      "metros": [{ "name": "地铁2号线", "lineNo": "2号线", "color": "140,194,32" }]
    }
  ]
}

stations[] 多项表示该站名对应多个物理站台。


线路

GET /v1/lines/detail

参数 类型 必填 说明
city_id string 城市 ID
line_id string 线路 ID(来自 /v1/search
lat / lng number string WGS-84,可选
{
  "line": {
    "lineId": "21283603183", "name": "71", "lineNo": "r95817", "direction": 0,
    "startSn": "延安东路外滩", "endSn": "申昆路枢纽站",
    "firstTime": "05:30", "lastTime": "23:30", "price": "2元", "stationsNum": 24
  },
  "stations": [
    { "order": 1, "sId": "...", "sn": "延安东路外滩", "wgsLat": 31.23, "wgsLng": 121.49, "physicalStId": "...", "namesakeStId": "...", "metros": [] }
  ],
  "buses": [
    { "busId": "...", "order": 2, "lat": 31.23, "lng": 121.47, "speed": 5.7, "capacity": 0 }
  ],
  "reverseDirection": {
    "lineId": "21283603182", "startSn": "申昆路枢纽站", "endSn": "延安东路外滩",
    "firstTime": "04:30", "lastTime": "22:30", "price": "2元"
  },
  "depDesc": "...", "preArrivalTime": "...", "targetOrder": 24
}

地铁线路返回 empty: truehint,不要重试,改用 /v1/stops/detail/v1/transit/plan

GET /v1/lines/route

参数 类型 默认 说明
city_id string 城市 ID
line_id string 线路 ID
include_shape boolean false false 仅站点标记(约 25 点);true 全部形状点(约 400–500 点)
{ "pointCount": 480, "stopCount": 23, "points": [{ "lat": 31.23, "lng": 121.49, "stopOrder": 1 }] }

GET /v1/lines/realtime

参数 类型 必填 说明
city_id string 城市 ID
line_id string 线路 ID
target_order integer string 等待站点在线路上的序号
station_id string 等待站点的 sId
lat / lng number string WGS-84;不知道用户位置时可用站点坐标
{
  "line": { "lineId": "21283603183", "name": "71", "direction": 0, "endSn": "申昆路枢纽站" },
  "targetOrder": 2,
  "realData": true,
  "buses": [
    { "busId": "...", "licence": "沪A12345", "order": 2, "lat": 31.23, "lng": 121.47, "speed": 5.7, "capacity": 0, "distanceToWaitStn": 90,
      "eta": { "travelTime": 25, "arrivalTime": 1779070466055, "displayTime": "10:14" } },
    { "busId": "...", "order": 3, "lat": 31.24, "lng": 121.46, "speed": 3, "capacity": 0, "eta": null }
  ],
  "note": "..."
}

上游只为最近一辆驶向目标站的车辆计算 eta,其余车辆 eta: null 属正常。

GET /v1/lines/buses

参数 类型 必填 说明
city_id / line_id string 城市 / 线路 ID
target_order integer string 等待站点序号
station_name string 等待站点名称
{
  "targetOrder": 2,
  "buses": [
    { "busId": "...", "licence": "沪A12345", "order": 2, "lat": 31.23, "lng": 121.47, "speed": 8.2, "capacity": 0,
      "nextStop": "西藏中路", "eta": { "travelTime": 214, "arrivalTime": 1779070686000, "displayTime": "10:18" } }
  ]
}

GET /v1/lines/timetable

参数 类型 必填 说明
city_id / line_id string 城市 / 线路 ID
line_no string 面向乘客的短名(search.lines[].name,如 71),不是 r95817
direction "0" | "1" 方向
{
  "line": { "lineId": "21283603183", "name": "71", "direction": 0, "startSn": "...", "endSn": "..." },
  "timeTableType": 2,
  "mode": "interval",
  "timetable": null,
  "note": "This line runs at a fixed interval — ..."
}

modescheduled(逐班时刻)、interval(固定间隔)、specialunknown。 查首末班请优先用 /v1/lines/detail

GET /v1/lines/refresh

参数 类型 必填 说明
city_id string 城市 ID
line_stn string 四元组 lineId,stopId,nextId,targetOrder,多条以 ; 分隔(nextId 可空,建议 ≤10 条)
curl "https://ts-api.tundrey.com/v1/lines/refresh?city_id=034&line_stn=21283603183,021-15232,,2;21283604388,021-8685,,4"
{
  "lines": [
    {
      "line": { "lineId": "21283603183", "name": "71", "direction": 0, "endSn": "申昆路枢纽站" },
      "depDesc": "10分钟后发车",
      "buses": [{ "busId": "...", "order": 2, "capacity": 0, "distanceToDest": 881, "eta": { "travelTime": 221, "arrivalTime": 1779070466055 } }]
    }
  ]
}

换乘规划

GET /v1/transit/plan

参数 类型 必填 说明
city_id string 城市 ID
origin_name / dest_name string 起点 / 终点名称(展示用)
origin_lat / origin_lng number string 起点坐标,GCJ-02
dest_lat / dest_lng number string 终点坐标,GCJ-02
strategy "0" | "1" | "2" | "3" 0 推荐(默认,含地铁)、1 少换乘、2 少步行、3 最短时间(上游常排除地铁)
{
  "origin": "121.49073,31.233021",
  "destination": "121.327,31.197",
  "distance": 17982,
  "plans": [
    {
      "duration": 3056, "walkingDistance": 1466, "distance": 19086, "tag": "直达", "transitCount": 1,
      "segments": [
        { "type": "walking", "distance": 837, "duration": 717 },
        { "type": "bus", "name": "地铁2号线", "lineType": 1, "departureStop": "人民广场", "arrivalStop": "虹桥2号航站楼",
          "viaStops": 8, "duration": 1800, "distance": 17620, "startTime": "05:37", "endTime": "23:30" }
      ]
    }
  ]
}

lineType0 公交、1 地铁。

延伸阅读:Coordinates-and-FieldsFAQ