银行汇率查询:跨境电商与留学缴费的多币种牌价管理

约 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)
加载中...