银行汇率查询:跨境电商与留学缴费的多币种牌价管理
约 14 分钟 进阶银行汇率查询跨境电商留学缴费多币种
# 银行汇率查询:跨境电商与留学缴费的多币种牌价管理
接口:银行汇率查询(apiCode=105)· 接入点:币种列表 / 汇率查询 / 汇率转换 / 历史汇率 · 免费接口(L0 基础版 100 次/天、1 QPS)· 适用人群:跨境电商、留学服务、财务团队 · 阅读时间:约 7 分钟 · 最后实测核对:2026-09-18
## 核心要点
- 四个接入点覆盖一条完整链路:币种列表取全集、汇率查询做展示、汇率转换做金额换算、历史汇率做对账留痕。
- 四个接入点属于同一个接口(apiCode=105),共用一套 AppKey 与鉴权方式,只有路径后缀不同。
- 实测两个数据口径需要注意:币种列表返回 45 条外币记录(不含 CNY),汇率查询不传参数返回 46 条(含 CNY)。
## 这条链路的四个环节
四个接入点属于同一个接口,共用一个 AppKey、一套鉴权方式,按路径后缀切换就能覆盖从取牌价到对账的完整链路。
跨境卖家的商品页要显示「$ 29.99 约合 ¥ 215」。留学中介要算「一年学费 $ 45,000 折合人民币多少」。财务要对每一笔换汇按当日牌价留底。这三件事看起来不同,用到的能力其实是同一套:拿到合法的货币代码、取牌价、换算金额、留一份可回溯的记录。
## 四个接入点分别在链路里的位置
| 环节 | 接入点 | 路径 | 在业务里的作用 |
|------|--------|------|----------------|
| 货币全集 | 外汇牌价币种列表 | `105-35` | 渲染下拉框、校验货币代码合法性 |
| 实时展示 | 汇率查询 | `105-30` | 取现汇 / 现钞买卖价与中行折算价 |
| 金额换算 | 汇率转换 | `105-31` | 把任意金额从 A 币种算到 B 币种 |
| 对账留痕 | 查询历史汇率 | `105-34` | 按月份或日期区间取历史牌价 |
## 一条封装好的调用示例
下面把「取牌价」和「换算金额」串起来,换成自己的 AppKey 即可运行。
Python(requests):
```python
import requests
APPKEY = "YOUR_APPKEY"
BASE = "https://route.showapi.com"
def _body(path: str, data: dict):
"""统一的返回处理:先判系统级,再判业务级。"""
js = requests.post(f"{BASE}/{path}", params={"appKey": APPKEY}, data=data, timeout=15).json()
if js.get("showapi_res_code") != 0:
raise RuntimeError(f"通道异常:{js.get('showapi_res_error')}")
body = js.get("showapi_res_body") or {}
if body.get("ret_code") != 0:
raise RuntimeError(f"业务失败:{body}")
return body
def currency_codes():
"""105-35:拿到全部可用货币代码,用于校验用户输入。"""
return {it["code"] for it in _body("105-35", {})["exchange_list"]}
def rate_table(code: str = ""):
"""105-30:不传 code 取全部,传 code 取单币种。"""
data = {"code": code} if code else {}
return _body("105-30", data)
def convert(from_code: str, to_code: str, amount: str):
"""105-31:三个必填参数,返回 money 与 rate。"""
body = _body("105-31", {"fromCode": from_code, "toCode": to_code, "money": amount})
return body["money"], body.get("rate")
if __name__ == "__main__":
codes = currency_codes()
print("可用货币:", len(codes), "种")
# 换算前先校验代码,避免把无效 code 传下去
for c in ("USD", "EUR"):
assert c in codes, f"{c} 不在币种列表内"
money, rate = convert("USD", "CNY", "100")
print("100 USD =", money, "CNY", "(比例", rate, ")")
```
cURL:
```bash
# 币种列表
curl -X POST "https://route.showapi.com/105-35?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded"
# 金额换算
curl -X POST "https://route.showapi.com/105-31?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
-d "fromCode=USD&toCode=CNY&money=100"
```
Node.js(fetch):
```javascript
const APPKEY = "YOUR_APPKEY";
const BASE = "https://route.showapi.com";
async function call(path, data = {}) {
const body = new URLSearchParams(data);
const res = await fetch(`${BASE}/${path}?appKey=${APPKEY}`, {
method: "POST",
body,
headers: { "content-type": "application/x-www-form-urlencoded" },
signal: AbortSignal.timeout(15000)
});
const json = await res.json();
if (json.showapi_res_code !== 0) throw new Error(`通道异常:${json.showapi_res_error}`);
if (json.showapi_res_body?.ret_code !== 0) throw new Error("业务失败");
return json.showapi_res_body;
}
const codes = (await call("105-35")).exchange_list.map((it) => it.code);
console.log("可用货币:", codes.length, "种");
```
## 数据表设计建议
多币种业务通常落两张表。一张存牌价快照,一张存换算流水。
```sql
-- 牌价快照:同一快照时间的一批数据整体入库,便于事后回溯
CREATE TABLE fx_rate_snapshot (
snapshot_day DATE NOT NULL COMMENT '接口返回的 day',
snapshot_time TIME NOT NULL COMMENT '接口返回的 time',
code VARCHAR(8) NOT NULL COMMENT '货币简码',
name VARCHAR(32) NOT NULL COMMENT '货币名称',
hui_in DECIMAL(18,6) NULL COMMENT '现汇买入价',
chao_in DECIMAL(18,6) NULL COMMENT '现钞买入价',
hui_out DECIMAL(18,6) NULL COMMENT '现汇卖出价',
chao_out DECIMAL(18,6) NULL COMMENT '现钞卖出价',
zhesuan DECIMAL(18,6) NULL COMMENT '中行折算价',
fetched_at DATETIME NOT NULL COMMENT '本行写入时间',
PRIMARY KEY (snapshot_day, snapshot_time, code)
) COMMENT='银行汇率查询牌价快照';
-- 换算流水:客服与财务事后可查,保留原始比例
CREATE TABLE fx_convert_log (
id BIGINT NOT NULL AUTO_INCREMENT,
from_code VARCHAR(8) NOT NULL,
to_code VARCHAR(8) NOT NULL,
amount DECIMAL(18,6) NOT NULL COMMENT '源金额,单位元',
result DECIMAL(18,6) NOT NULL COMMENT '接口返回的 money',
rate DECIMAL(18,8) NULL COMMENT '接口返回的 rate',
created_at DATETIME NOT NULL,
PRIMARY KEY (id),
KEY idx_created (created_at)
) COMMENT='汇率换算流水';
```
把 `rate` 一起入库的好处是,事后核对某笔换算时不用再去拉当日牌价重算。这个字段在接口文档里没有列出,但 2026-09-18 实测 105-31 会返回它。
五个价位字段都允许为 NULL:实测 46 条记录里有 17 种货币存在空价位,落库时按可空处理,读出来给前端前再统一转成展示串。
## 对账环节怎么用历史接入点
对账要的是「某个已过去日期的牌价」。按月份取一次拿到整月,把每日的 `publish_time` 与 `middle_rate` 落成时序点,就能在事后回答「8 月 31 日那笔换汇按当日牌价应该是多少」。
2026-09-18 实测两个需要注意的行为。第一,`list` 按 `publish_time` 倒序返回,落库前先排序。第二,请求区间超过 90 天时接口不报错,`list` 最多返回 90 条,长跨度取数请按 90 天分段,并以 `list` 首尾的 `publish_time` 作为真实区间依据。
## FAQ
**Q1:四个接入点要分别申请吗?**
不需要。它们属于同一个接口(apiCode=105),共用一个 AppKey、一套鉴权方式,只是请求路径后缀不同(105-30 / 31 / 34 / 35)。
**Q2:换算结果能直接写进合同或账单吗?**
接口数据为延迟数据、仅供参考,正式账单金额以银行实际成交价为准。接口返回值适合做展示与预估。
**Q3:多币种字典从哪里取?**
用币种列表接入点(105-35)的 `exchange_list[].code`,不要硬编码。注意实测该列表返回 45 条外币记录、不含人民币,换算器场景需要自行补上 CNY。
**Q4:同一次换算里的 `rate` 可以落库吗?**
可以,而且建议落。实测 105-31 返回的 `rate` 与 105-30 的现汇买入价能对上(100 USD = 669.6100 CNY,rate 为 6.6961),落库后事后核对不需要重新取牌价。
**Q5:为什么落库时五个价位字段要允许为空?**
实测不传 `code` 时返回的 46 条记录里,17 种货币存在空字符串价位(11 种缺现汇价、6 种缺现钞价),表结构按可空设计才装得下。
## 下一步阅读
- [银行汇率查询:汇率转换只需 3 个必填参数](https://www.showapi.com/guides/exchange-rate-convert-guide-105):换算参数与 `rate` 字段的细节。
- [银行汇率查询历史汇率:按月取还是按区间取](https://www.showapi.com/guides/exchange-rate-history-guide-105):对账环节取历史数据的两种方式。
- [银行汇率查询:企业汇率看板的落库与走势实现](https://www.showapi.com/guides/exchange-rate-finance-dashboard-105):把落库的表变成一块能看的看板。
- **本系列共 13 篇**:查看[银行汇率查询指南总目录](https://www.showapi.com/guides/exchange-rate-guides-105)





