接口文档
版本 v1,协议 HTTPS + JSON。所有数据接口均需签名鉴权,按返回条数计费。
快速开始
- 注册账号并登录客户控制台(需填写你自己的网站域名与服务器地址)。
- 在 API 密钥 页面创建密钥,填写调用服务器的出口 IP。
- 管理员人工审核密钥,并把对应 IP 写入白名单(未审核通过的密钥无法调用)。
- 按下方规则对请求签名,调用
https://api.jxphotos.cn/api/v1/...。 - 在控制台查看调用流水与余额;余额不足请联系管理员充值。
接口根地址:
https://api.jxphotos.cn;
余额与用量查询:GET /api/v1/balance、GET /api/v1/usage(均需签名)。
鉴权与签名
每个请求都必须携带以下 4 个请求头,缺一不可:
| 请求头 | 说明 |
|---|---|
| X-Api-Key | 密钥 ID(形如 jxak_xxxxxxxxxxxxxxxx),控制台可见。 |
| X-Api-Timestamp | Unix 时间戳(秒)。与服务器时间偏差不得超过 300 秒。 |
| X-Api-Nonce | 一次性随机数,8-64 位字母/数字/下划线/短横线,每次请求必须不同。 |
| X-Api-Signature | 小写十六进制 HMAC-SHA256 签名。 |
待签名内容(字符串)
按下列顺序逐行拼接,共 6 行,行之间用换行符 \n 分隔,末尾不加换行:
HTTP 方法(大写,如 GET) 请求路径(不含查询串,如 /api/v1/train-units) 规范化查询串(参数名按字典序升序,RFC3986 编码) 时间戳(十进制秒) 随机数 nonce 请求体的 SHA-256 十六进制小写(GET 无请求体时固定为 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)
规范化查询串规则:解析原始查询串后按参数名升序排序,同名参数按值升序,
使用 RFC3986 编码(空格为 %20,百分号编码用大写十六进制)。
无查询参数时该行为空字符串。
签名:signature = hex(HMAC-SHA256(待签名内容, API_SECRET))。
示例待签名内容
GET /api/v1/train-units page=1&per_page=20&train_type=%E5%86%85%E7%87%83%E6%9C%BA%E8%BD%A6 1750000000 a1b2c3d4e5f60718 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
代码示例
PHP:
<?php
$keyId = 'jxak_xxxxxxxxxxxxxxxx';
$secret = 'jxsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$path = '/api/v1/train-units';
$query = ['train_type' => '内燃机车', 'page' => 1, 'per_page' => 20];
ksort($query, SORT_STRING);
$queryString = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(8));
$canonical = implode("\n", [
'GET',
$path,
$queryString,
$timestamp,
$nonce,
hash('sha256', ''), // GET 无请求体
]);
$signature = hash_hmac('sha256', $canonical, $secret);
$ch = curl_init('https://api.jxphotos.cn' . $path . '?' . $queryString);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Api-Key: ' . $keyId,
'X-Api-Timestamp: ' . $timestamp,
'X-Api-Nonce: ' . $nonce,
'X-Api-Signature: ' . $signature,
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python:
import hashlib, hmac, secrets, time, urllib.parse, requests
key_id = "jxak_xxxxxxxxxxxxxxxx"
secret = "jxsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
path = "/api/v1/train-units"
params = {"train_type": "内燃机车", "page": 1, "per_page": 20}
query = urllib.parse.urlencode(sorted(params.items()), quote_via=urllib.parse.quote)
timestamp, nonce = str(int(time.time())), secrets.token_hex(8)
canonical = "\n".join(["GET", path, query, timestamp, nonce, hashlib.sha256(b"").hexdigest()])
signature = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
resp = requests.get("https://api.jxphotos.cn" + path, params=params, headers={
"X-Api-Key": key_id,
"X-Api-Timestamp": timestamp,
"X-Api-Nonce": nonce,
"X-Api-Signature": signature,
}, timeout=10)
print(resp.status_code, resp.json())
Node.js:
const crypto = require('crypto');
const keyId = 'jxak_xxxxxxxxxxxxxxxx';
const secret = 'jxsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const path = '/api/v1/train-units';
const params = new URLSearchParams({ train_type: '内燃机车', page: '1', per_page: '20' });
params.sort();
const query = params.toString(); // URLSearchParams 已按 RFC3986 编码
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(8).toString('hex');
const canonical = ['GET', path, query, timestamp, nonce,
crypto.createHash('sha256').update('').digest('hex')].join('\n');
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex');
const res = await fetch(`https://api.jxphotos.cn${path}?${query}`, {
headers: {
'X-Api-Key': keyId,
'X-Api-Timestamp': timestamp,
'X-Api-Nonce': nonce,
'X-Api-Signature': signature,
},
});
console.log(res.status, await res.json());
通用查询参数
| 参数 | 类型 | 说明 |
|---|---|---|
| page | int | 页码,从 1 开始,默认 1,最大 1000。 |
| per_page | int | 每页条数,1-100,默认 20。计费按实际返回条数计算。 |
| keyword | string | 关键词模糊匹配(也支持 q),长度 ≤ 100。 |
各数据集还支持等值筛选参数(见下方对应章节)。所有参数必须一并参与签名计算,否则会返回 40105。
响应格式
统一信封:code 为 0 表示成功;非 0 时 msg 为原因,data 可能带补充字段。
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "train_units",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": { "train_type": "内燃机车" },
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "99.8"
},
"items": [ { "unit_number": "HXD1-0001", "model_name": "HXD1" } ]
},
"request_id": "1f2c3d4e5a6b7c8d"
}
total为符合筛选条件的总条数,count为本次实际返回条数。billed.amount为本次扣费金额(元),billed.balance为扣费后余额。request_id可用于对账与故障排查。- 空字符串统一输出为
null;数值型字段输出为 JSON 数字。
铁路车号台账
在售 · 0.01 元/条机车 / 动车组车号明细,含所属车型、配属、制造厂家。
GET
/api/v1/train-units
| 记录数 | 按需咨询 |
|---|---|
| 单价 | 0.01 元/条 |
| 等值筛选 | unit_number</code> <code class="inline">model_name</code> <code class="inline">train_type</code> <code class="inline">manufacturer</code> <code class="inline">bureau |
| 关键词范围 | unit_number / model_name / name_cn / manufacturer / bureau |
| 排序 | unit_number ASC |
返回字段
- unit_number 车号
- model_name 车型
- name_cn 车型中文名
- series_name 系列
- train_type 类型
- manufacturer 厂家
- bureau 配属
示例请求
https://api.jxphotos.cn/api/v1/train-units?unit_number=<示例值>&page=1&per_page=20
示例响应
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "train_units",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": [],
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "<扣费后余额>"
},
"items": [
{
"unit_number": "<值>",
"model_name": "<值>",
"name_cn": "<值>",
"series_name": "<值>",
"train_type": "<值>",
"manufacturer": "<值>",
"bureau": "<值>"
}
]
},
"request_id": "<请求唯一标识>"
}
铁路车型资料
在售 · 0.01 元/条车型型号库,含最高速度、功率、编组、简介等参数。
GET
/api/v1/train-models
| 记录数 | 按需咨询 |
|---|---|
| 单价 | 0.01 元/条 |
| 等值筛选 | model_name</code> <code class="inline">train_type</code> <code class="inline">series_name</code> <code class="inline">manufacturer_name</code> <code class="inline">unit_count</code> <code class="inline">max_speed_kmh |
| 关键词范围 | model_name / name_cn / series_name / manufacturer_name / formation |
| 排序 | model_name ASC |
返回字段
- model_name 车型
- name_cn 中文名
- series_name 系列
- manufacturer_name 厂家
- train_type 类型
- unit_count 在册车号数
- max_speed_kmh 最高速度
- power_kw 功率
- formation 编组
- summary 简介
示例请求
https://api.jxphotos.cn/api/v1/train-models?model_name=<示例值>&page=1&per_page=20
示例响应
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "train_models",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": [],
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "<扣费后余额>"
},
"items": [
{
"model_name": "<值>",
"name_cn": "<值>",
"series_name": "<值>",
"manufacturer_name": "<值>",
"train_type": "<值>",
"unit_count": "<值>",
"max_speed_kmh": "<值>",
"power_kw": "<值>",
"formation": "<值>",
"summary": "<值>"
}
]
},
"request_id": "<请求唯一标识>"
}
车站资料
在售 · 0.01 元/条铁路车站名录,含电报码、所属城市、经纬度、经过线路。
GET
/api/v1/stations
| 记录数 | 按需咨询 |
|---|---|
| 单价 | 0.01 元/条 |
| 等值筛选 | name</code> <code class="inline">city</code> <code class="inline">region</code> <code class="inline">country</code> <code class="inline">telegraph_code</code> <code class="inline">station_type |
| 关键词范围 | name / name_en / pinyin / telegraph_code / city / region / lines |
| 排序 | name ASC |
返回字段
- name 车站名
- name_en 英文名
- pinyin 拼音
- telegraph_code 电报码
- city 城市
- region 省/州
- country 国家
- station_type 类型
- business 业务
- lines 线路
- lat 纬度
- lng 经度
示例请求
https://api.jxphotos.cn/api/v1/stations?name=<示例值>&page=1&per_page=20
示例响应
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "stations",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": [],
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "<扣费后余额>"
},
"items": [
{
"name": "<值>",
"name_en": "<值>",
"pinyin": "<值>",
"telegraph_code": "<值>",
"city": "<值>",
"region": "<值>",
"country": "<值>",
"station_type": "<值>",
"business": "<值>",
"lines": "<值>",
"lat": "<值>",
"lng": "<值>"
}
]
},
"request_id": "<请求唯一标识>"
}
飞机注册号资料
在售 · 0.01 元/条注册号台账,含国家、机型、序列号、状态等。出于隐私保护不含机主姓名。
GET
/api/v1/aircraft-registrations
| 记录数 | 按需咨询 |
|---|---|
| 单价 | 0.01 元/条 |
| 等值筛选 | registration</code> <code class="inline">country_code</code> <code class="inline">registration_type</code> <code class="inline">model_name</code> <code class="inline">icao_type_code</code> <code class="inline">manufacturer_name</code> <code class="inline">serial_number</code> <code class="inline">status</code> <code class="inline">year_manufactured |
| 关键词范围 | registration / serial_number / model_name / manufacturer_name / operator_name / airline_name / icao_type_code |
| 排序 | registration ASC |
返回字段
- registration 注册号
- country_code 国家代码
- registration_type 注册类型
- serial_number 序列号
- manufacturer_name 制造商
- model_name 机型
- icao_type_code ICAO 机型代码
- aircraft_category 类别
- engine_type 发动机类型
- engine_count 发动机数量
- seats 座位数
- year_manufactured 出厂年份
- owner_type 持有方类型
- operator_name 运营人
- status 状态
示例请求
https://api.jxphotos.cn/api/v1/aircraft-registrations?registration=<示例值>&page=1&per_page=20
示例响应
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "aircraft_registrations",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": [],
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "<扣费后余额>"
},
"items": [
{
"registration": "<值>",
"country_code": "<值>",
"registration_type": "<值>",
"serial_number": "<值>",
"manufacturer_name": "<值>",
"model_name": "<值>",
"icao_type_code": "<值>",
"aircraft_category": "<值>",
"engine_type": "<值>",
"engine_count": "<值>",
"seats": "<值>",
"year_manufactured": "<值>",
"owner_type": "<值>",
"operator_name": "<值>",
"status": "<值>"
}
]
},
"request_id": "<请求唯一标识>"
}
铁路车型分类字典
在售 · 0.01 元/条机车 / 动车组 / 高速列车分类字典(大类、子类、名称)。
GET
/api/v1/railway-types
| 记录数 | 按需咨询 |
|---|---|
| 单价 | 0.01 元/条 |
| 等值筛选 | name</code> <code class="inline">category</code> <code class="inline">subcategory |
| 关键词范围 | name / category / subcategory |
| 排序 | id ASC |
返回字段
- name 名称
- category 大类
- subcategory 子类
示例请求
https://api.jxphotos.cn/api/v1/railway-types?name=<示例值>&page=1&per_page=20
示例响应
{
"code": 0,
"msg": "ok",
"data": {
"dataset": "railway_types",
"page": 1,
"per_page": 20,
"total": 128,
"count": 20,
"has_more": true,
"filters": [],
"billed": {
"unit_price": "0.01",
"amount": "0.2",
"balance": "<扣费后余额>"
},
"items": [
{
"name": "<值>",
"category": "<值>",
"subcategory": "<值>"
}
]
},
"request_id": "<请求唯一标识>"
}
计费与余额
- 计费公式:本次费用 = 数据集单价 × 本次返回条数;返回 0 条不扣费。
- 单价由管理员在后台为每个数据集单独设置,调整后立即生效(以请求时的单价为准)。
- 余额不足时接口返回
40201,不会返回数据、不会欠费。 - 余额由管理员充值/调整,客户可在 余额明细 中查看每一笔变动。
- 数据集被管理员停售后返回
40304,恢复上架后即可继续调用。
限流与风控
- 每秒最多 10 次请求(返回
42901)。 - 每分钟最多 120 次请求(返回
42902)。 - 触发限流、IP 不在白名单、签名错误等异常时,服务器会立即断开连接(响应头
Connection: close)。 - 短时间内反复触发限流会导致密钥或 IP 被临时封禁(默认 10 分钟,返回
40303)。 - 每个请求的随机数在 300 秒内只能使用一次,重复使用返回
40104。
错误码
| code | HTTP | 说明 | 处理建议 |
|---|---|---|---|
| 40101 | 401 | 缺少鉴权请求头 | 检查 X-Api-Key / X-Api-Timestamp / X-Api-Nonce / X-Api-Signature 是否齐全 |
| 40102 | 401 | 密钥不存在或未通过审核 | 确认密钥已由管理员审核通过,且未被停用 |
| 40103 | 401 | 时间戳超出允许范围 | 服务器时间需与标准时间同步(允许偏差 300 秒) |
| 40104 | 401 | 随机数重复(疑似重放) | 每次请求使用新的唯一随机数 |
| 40105 | 401 | 签名校验失败 | 核对待签名字符串拼装顺序与 Secret |
| 40301 | 403 | 调用方 IP 不在白名单内 | 联系管理员把该服务器出口 IP 加入白名单 |
| 40302 | 403 | 账号或密钥已被停用 | 联系管理员恢复账号状态 |
| 40303 | 403 | 触发风控被临时封禁 | 等待封禁到期(默认 600 秒)后重试 |
| 40304 | 403 | 数据集已停售 | 该数据集暂未开放,请联系管理员 |
| 40201 | 402 | 余额不足 | 联系管理员充值后重试 |
| 42901 | 429 | 超过每秒调用限制(10 次/秒) | 降低并发,连接会被立即断开 |
| 42902 | 429 | 超过每分钟调用限制(120 次/分钟) | 降低频率,连接会被立即断开 |
| 40001 | 400 | 请求参数不合法 | 按文档检查查询参数与取值格式 |
| 50001 | 500 | 服务端异常 | 稍后重试;持续出现请联系管理员 |