本页目录
CrestRate API 接口文档
多源聚合的汇率接口,为跨币种收款和付款的企业而做。你决定汇率站在哪一边,点差按 API key 配置,报价单同时锁定汇率和点差。
- 基地址 —
https://api.crestrate.com。汇率接口都在/v1下,例如https://api.crestrate.com/v1/rate - 第一次接入 — 先看快速开始,四段可复制的代码带你跑通第一次调用
- 机器可读规范 — OpenAPI 3.1
- 套餐、配额与限速 — 定价
- 服务状态 — https://crestrate.com/zh/status
适用场景
用一种货币标价、用另一种货币结算,就用得上。我们不按行业划分客户,常见用法如下:
- 跨境电商 — 商品标价换算成客户的货币
- SaaS 与订阅制 — 按客户本地货币出账单
- 访日游客消费 — 酒店、零售、免税店、收银系统以日元定价,游客用港币、人民币、美元、欧元付款
- B2B 进出口贸易 — 按买方货币开发票,报价有效期内用报价单锁价
- 平台与市场 — 向买家收款用
strategy=max,给卖家结算用strategy=min - 旅游、留学、签证等中介 — 按客户的货币报价
- 游戏与数字商品 — 按地区定价
支持的币种
以下币种提供实时数据,base 与 quote 可任意组合:
| 币种 | 代码 | 金额最小单位 |
|---|---|---|
| 美元 | USD |
0.01 |
| 日元 | JPY |
1 |
| 欧元 | EUR |
0.01 |
| 港币 | HKD |
0.01 |
| 人民币 | CNY |
0.01 |
暂时无法提供实时数据: TWD、SGD、GBP、AUD、KRW、MYR、THB,稳定后开放。
在此之前,请求中使用这些代码会返回 HTTP 422 currency_not_available,supported 字段列出当前可用的币种。完全无法识别的代码返回 HTTP 400 unsupported_currency。请求中的币种代码不区分大小写,响应中一律大写。
汇率是怎么选出来的
每次请求都会把当前健康的全部数据源一起纳入计算,而不是只问一家:
- 各源的汇率表统一归一化到同一基准,你要的货币对按交叉汇率算出来
- 数据过期的源、不覆盖该货币对的源,先剔除
- 从最新鲜的那一档源(实时 → 小时级 → 每日)取中位数作为基准。 这是对「当前市场价」最可靠的估计
- 与基准偏离超过故障阈值的源被判定为数据损坏,剔除
- 按
strategy在幸存的源里选价:max取最高、min取最低、median取最接近中位数的那个。 再做双向钳制:高于封顶线cap_rate就压回封顶线,低于保底线floor_rate就抬回保底线 - 按收付方向叠加点差:收款方往上加,付款方往下减
返回里始终写明最终汇率来自哪个源、其他源各报了多少、以及任何被剔除的源和机器可读的剔除原因(excluded_code)。数据源用稳定的匿名代号标识,如 source_a。
有效源不足时返回 HTTP 503 no_rate,而不是给出一个我们无法担保的数字。
你决定汇率站在哪一边
同一个货币对,收钱时汇率越高越好,付钱时越低越好。用 strategy 告诉我们你在哪一边,返回里的 side 会写明本次按哪一边算。
strategy |
side |
对谁有利 | 典型用途 |
|---|---|---|---|
max(默认) |
charge |
收款方:选最高汇率,同样的标价收到更多 | 电商、SaaS、酒店、B2B 开票 |
min |
pay |
付款方:选最低汇率,同样的应付额付出更少 | 平台给卖家结算、给海外供应商付款 |
median |
charge |
中立:选最接近各源中位数的汇率 | 会计记账、对内报表 |
strategy 不区分大小写,其他取值返回 HTTP 400 bad_request。side 同时决定点差方向和金额取整方向:
| 项目 | charge(收款方) |
pay(付款方) |
|---|---|---|
| 点差 | 汇率往上,客户多付 | 汇率往下,你少付 |
payable 取整 |
向上取整到最小货币单位 | 向下取整到最小货币单位 |
gain_vs_mid |
payable - mid_payable(多收的) |
mid_payable - payable(少付的) |
两个方向都有保护。 选出的汇率会与新鲜度基准 anchor_rate 比较:高于封顶线 cap_rate 就压回(capped: true),低于保底线 floor_rate 就抬回(floored: true)。收款时不会明显高于实时市场,付款时不会明显低于实时市场 —— 对方拿公开汇率核对也站得住。点差是你主动配置的,在钳制之后才叠加。
点差
点差是你在选出的汇率上额外加的幅度,单位基点(bps),100 基点 = 1%。
| 项目 | 说明 |
|---|---|
| 在哪设置 | 控制台的 API key 列表,每把 key 单独设置 |
| 默认点差 | 这把 key 在所有币种上使用的点差 |
| 按币种单独设置 | 按 quote 币种覆盖默认点差,例如 HKD 120 基点、JPY 200 基点。只能为提供实时数据的币种单独设置 |
| 取值范围 | 0 ~ 1000 基点(0% ~ 10%)。设为 0 表示明确不加点差 |
| 生效时间 | 保存后立即生效,下一次请求就用新值 |
| 报价单 | 点差在创建报价单时锁定。之后改点差,已发出的报价单不受影响 |
优先级从高到低,返回里的 markup_source 会写明本次用的是哪一个:
- 该 key 对此币种的单独设置 →
key_currency - 该 key 的默认点差 →
key_default - 平台默认 →
platform
同币种对(如 USD → USD)没有发生兑换,不加点差,markup_source 为 none。
方向和取整都跟着 side 走,结果始终对你有利。 收款方:raw_rate × (1 + markup_bps/10000),金额向上取整;付款方:raw_rate × (1 - markup_bps/10000),金额向下取整。
算例(数字仅作示例,不是实时行情;为便于对比,假设两种情况选出的汇率都是 7.8000):一笔 1,000 美元的订单,用港币结算,点差 150 基点(1.5%)。
| 场景 | 不加点差 | 点差 150 基点 | 差额 |
|---|---|---|---|
你在收款(strategy=max) |
汇率 7.8000,客户付 HK$7,800.00 | 汇率 7.9170,客户付 HK$7,917.00 | 多收 HK$117.00 |
你在付款(strategy=min) |
汇率 7.8000,你付 HK$7,800.00 | 汇率 7.6830,你付 HK$7,683.00 | 少付 HK$117.00 |
先预览再保存。 在控制台设置点差时有效果预览:调数值时当场显示客户多付多少、你少付多少。
披露。 在对加价有披露要求的地区(例如欧盟面向消费者的支付),请向你的客户披露加价。
报价单锁价
报价单把你展示给客户的价格冻结到过期为止,展示和付款之间的汇率波动不会造成金额对不上。
POST /v1/quotes在创建时锁定最终汇率rate、当时生效的点差markup_bps和结算金额payable- 之后在控制台修改这把 key 的点差,不会改变已发出的报价单
- 报价单在
ttl_seconds内有效(目前为 900 秒,即 15 分钟)。请从响应读取,不要写死 - 保存
quote_id,客户付款时用GET /v1/quotes/{quote_id}取回;过了expires_at会返回 404,此时应重新创建报价单
网站演示
首页上的在线演示只用于体验,不是可以接入的接口:
- 数据延迟 1 小时:用各数据源 1 小时前的最新快照计算,结果旁边标出数据时间
- 每次请求都经过无感的人机验证(Cloudflare Turnstile)
- 使用平台默认点差,按网段和全站限流,高峰期可能提示繁忙
- 不接受 API key,不计量,不占用任何账号的配额
需要实时数据请在控制台免费创建 API key。
接口参考
鉴权
所有 /v1 接口都必须带 API key,没有匿名访问。
| 请求头 | 示例 |
|---|---|
X-API-Key |
X-API-Key: <你的 key> |
Authorization |
Authorization: Bearer <你的 key> |
- 任选其一;两者都带时以
X-API-Key为准 - 在控制台创建和撤销 key。需先完成邮箱验证,每个账号最多同时持有 10 把有效 key。明文只显示一次
- 撤销后的 key 立即失效(HTTP 401
invalid_api_key) - 请从你的服务端调用。
/v1响应不带 CORS 头;嵌在网页或手机 App 里的 key 任何人都能拿走 GET /health与GET /openapi.json不需要 key
通用约定
| 约定 | 说明 |
|---|---|
| 汇率与金额一律是字符串 | 不是 JSON number。JSON 的 number 是 IEEE 754 双精度,0.05117904 这类值解析后会丢精度,金额算错。请用 Decimal(Python)/ BigDecimal(Java)/ decimal.js(JS)解析。汇率固定 8 位小数 |
| 时间 | 一律 ISO 8601 UTC 字符串,如 2026-09-14T10:38:01Z。需要做算术的地方额外给 *_unix(Unix 秒,浮点) |
| 百分比 | 字符串,单位是 %(不是小数)。"0.1791" 表示 0.1791%,不是 17.91% |
| 币种代码 | ISO 4217。请求中不区分大小写,响应中一律大写。见上文「支持的币种」 |
| base / quote | base = 标价币种,quote = 结算币种(收款时是客户支付的币种,付款时是你付出的币种)。汇率含义恒为「1 单位 base 能换多少 quote」 |
| 缓存与 Cookie | 汇率响应带 Cache-Control: no-store。接口从不设置 Cookie |
限速与月配额
每个套餐有一个限速(稳定速率加短时突发)和一个月请求配额,公布在定价页。
- 两者都按账号计算,不按 key。 同一账号下的所有 API key 共享同一个限速和同一份月配额,多建 key 不会提高任何一项。
X-Quota-*响应头显示的是整个账号的合计 - 月配额在每个自然月开始时(UTC)重置
- 通过鉴权和限额检查的请求,无论结果如何都计入配额 —— 包括 400、404、422、503。被 401、403、429 拒绝的请求不计入
- 对
/v1接口发出的HEAD请求与GET完全相同地处理(完整执行汇率计算),因此同样计入配额和限速 - 不存在的路径返回 404
not_found,不计量
所有 /v1 响应(包括错误响应)都带以下响应头:
| 响应头 | 含义 |
|---|---|
X-RateLimit-Limit |
最大突发量:可以连续发出多少个请求 |
X-RateLimit-Remaining |
此刻不必等待还能发出多少个请求 |
X-RateLimit-Reset |
下一个请求名额可用的 Unix 时间(秒) |
X-Quota-Limit |
账号的月配额。0 表示不限 |
X-Quota-Used |
账号本月已用请求数,含本次 |
X-Quota-Remaining |
本月剩余请求数。X-Quota-Limit 为 0(不限)时恒为 0,请先看上限 |
X-Request-Id |
本次请求的 ID。联系支持时请附上 |
Retry-After |
需等待的秒数。只随 429 rate_limited 返回 |
请求无法归属到某个账号时(缺少或无效的 key、账号停用或邮箱未验证、请求体超限、内部错误),限速与配额头给出的是与任何账号无关的中性默认值。
触发限额时
| 响应 | 含义 | 怎么办 |
|---|---|---|
429 rate_limited |
短时间内请求过多 | 等待 Retry-After 秒(响应体也有 retry_after)后重试 |
429 quota_exceeded |
账号本月配额已用完。硬性阻断:不做超额计费,不带 Retry-After |
不要重试。升级套餐(upgrade_url 为定价页的绝对地址)或等下个月。响应体带 used 与 quota |
请求处理顺序
请求按以下顺序检查,第一个不通过的检查决定响应:
- 请求体大小:超过 16 KiB → 413
payload_too_large - 缺少 API key → 401
api_key_required;key 无效或已撤销 → 401invalid_api_key - 账号已停用 → 403
account_disabled;邮箱未验证 → 403email_not_verified - 限速 → 429
rate_limited;月配额 → 429quota_exceeded - 参数 → 400
bad_request/ 400unsupported_currency/ 422currency_not_available(此时已计入配额) - 定价 → 有效源不足 503
no_rate;数据存储短暂不可达 503storage_unavailable
GET /v1/rate
取单个货币对的最终汇率,并附全部数据源的明细。
查询参数
| 参数 | 必填 | 说明 |
|---|---|---|
base |
是 | 标价币种。别名 from |
quote |
是 | 结算币种。别名 to |
strategy |
否 | 汇率站在哪一边:max(默认,收款)/ min(付款)/ median(中立)。不区分大小写 |
同币种对(如 base=USD"e=USD)返回汇率 1.00000000,chosen_provider 与 anchor_tier 为 identity。
响应:顶层字段
| 字段 | 类型 | 说明 |
|---|---|---|
base |
string | 标价币种 |
quote |
string | 结算币种 |
rate |
string | 最终汇率,算金额就用它。收款方(side=charge)为 raw_rate × (1 + markup_bps/10000),付款方(side=pay)为 raw_rate × (1 - markup_bps/10000)。markup_bps 为 0 时等于 raw_rate |
raw_rate |
string | 加点差前的汇率。按 strategy 在各源中选出;触及 cap_rate / floor_rate 时已被钳制 |
mid_rate |
string | 有效源的中位数,约等于市场中间价。可用来衡量你比市场高出多少 |
low_rate |
string | 有效源中的最低汇率。strategy=min 且未触及保底线时等于 raw_rate |
high_rate |
string | 有效源中的最高汇率。strategy=max 且未触及封顶线时等于 raw_rate |
markup_bps |
int | 本次实际使用的点差,单位基点(100 基点 = 1%)。同币种对恒为 0 |
markup_source |
string | 点差来源:key_currency(该 key 对此币种的单独设置)/ key_default(该 key 的默认点差)/ platform(平台默认)/ none(同币种对,不加点差) |
strategy |
string | 本次使用的选价策略:max / median / min |
side |
string | 本次站在哪一边:charge(收款方;max 与 median)/ pay(付款方;min)。点差方向与取整方向跟随它 |
chosen_provider |
string | 最终汇率来自哪个源,匿名代号,如 source_a。同币种对为 identity |
source_count |
int | 参与定价的有效源数量(不含被剔除的) |
spread_vs_mid_pct |
string | 最终汇率相对 mid_rate 的偏离,单位 %,4 位小数。收款时通常为正,付款时通常为负 |
anchor_rate |
string | 新鲜度基准。剔除异常值与封顶/保底都以它为准;取最新鲜那一档的中位数 |
anchor_tier |
string | 基准来自哪一档:realtime / hourly / daily / all / identity。退到 daily 或 all 说明新鲜源都暂不可用,报价可能偏离市场 |
anchor_notes |
string[] | 更新鲜的档位为何没被采用为基准,英文说明。正常情况下为空数组 |
cap_rate |
string | null | 封顶线:anchor_rate 加一个固定幅度。raw_rate 不会超过它。同币种对为 null |
capped |
bool | true 表示选出的汇率超过封顶线、被压了回来。说明市场在动而较慢的源还没跟上,值得告警 |
floor_rate |
string | null | 保底线:anchor_rate 减去同样的幅度。raw_rate 不会低于它。同币种对为 null |
floored |
bool | true 表示选出的汇率低于保底线、被抬了回来。多见于 strategy=min |
sources |
object[] | 全部数据源明细,含被剔除的源。见下表 |
generated_at |
string | 本次响应生成时间(ISO 8601 UTC) |
generated_at_unix |
float | 同上,Unix 秒 |
响应:sources[] 每一项
| 字段 | 类型 | 说明 |
|---|---|---|
provider |
string | 稳定的匿名源代号,如 source_a |
label |
string | 展示名,如 Source A |
data_freq |
string | null | 该源自身数据的更新频率:realtime / hourly / daily |
rate |
string | null | 该源给出的 base→quote 汇率。null 表示该源不覆盖此货币对 |
vs_anchor_pct |
string | null | 该源相对 anchor_rate 的偏离,单位 %(正数表示更高) |
fetched_at |
string | 我们抓取它的时间(ISO 8601 UTC) |
age_seconds |
float | 距那次抓取过了多少秒 |
source_time |
string | null | 该源自称的数据时间。null 表示该源不提供 |
used |
bool | 是否参与了本次定价 |
chosen |
bool | 是否就是被选中的那个源 |
excluded_code |
string | null | 机器可读的剔除原因;参与定价时为 null。监控请匹配它 |
excluded_reason |
string | null | 给人看的英文剔除原因;参与定价时为 null。文案可能调整,不要解析 |
excluded_code 的取值
excluded_code |
excluded_reason 示例 |
含义 | 怎么办 |
|---|---|---|---|
missing_currency |
Source does not cover this currency pair |
该源不覆盖此货币对 | 正常,其他源会补上 |
snapshot_stale |
Snapshot is stale (9000s > 7200s) |
太久没从该源抓到新数据 | 其他源会补上;持续出现可看状态页 |
deviates_from_anchor |
Deviates 12.5% from the realtime tier anchor, beyond +/-5%; treated as a data fault |
该源数值离基准太远 | 该源数据很可能损坏,你这边无需处理 |
GET /v1/rates
一次取多个货币对的汇率表。每行是 GET /v1/rate 的精简版,不含 sources 明细。
查询参数
| 参数 | 必填 | 说明 |
|---|---|---|
base |
否 | 逗号分隔的标价币种,如 USD,EUR。空项与重复项会被忽略 |
quote |
否 | 逗号分隔的结算币种,如 JPY,HKD |
省略参数时使用服务的默认币种网格;如果你的集成依赖确切的行,请显式传入两个参数。
列表里有无法识别的代码时整个请求返回 400 unsupported_currency;有暂时无法提供实时数据的币种时返回 422 currency_not_available。先整体检查 base 列表,再检查 quote:同一列表内无法识别的代码优先于暂时无法提供实时数据的币种报错,但 base 的问题总是先报,因此 base 含暂时无法提供实时数据的币种、同时 quote=ZZZ 时返回 422。
各行使用平台默认点差,不使用你这把 key 的点差。 需要应用你自己的点差时,请用
GET /v1/rate或GET /v1/convert。
响应
| 字段 | 类型 | 说明 |
|---|---|---|
rows |
object[] | 每个 base × quote 组合一行 |
generated_at / generated_at_unix |
string / float | 生成时间 |
rows[] 每一项
| 字段 | 类型 | 说明 |
|---|---|---|
base / quote |
string | 货币对 |
final_rate |
string | 按平台默认点差计算的最终汇率 |
raw_rate |
string | 加点差前 |
mid_rate |
string | 各源中位数 |
chosen_provider |
string | 被选中的源(匿名代号) |
source_count |
int | 有效源数量 |
markup_bps |
int | 使用的点差(平台默认) |
spread_pct |
string | 相对中间价的溢价,单位 %,3 位小数 |
anchor_tier |
string | 基准档位 |
capped |
bool | 是否触及封顶线 |
error |
string | null | 不为 null 时该行没有汇率:只有 base、quote、error 三个字段。典型原因是该货币对有效源不足。使用每一行之前务必判空 |
GET /v1/convert
把标价币种的金额换算成结算金额。金额取整到币种的最小单位(JPY 到 1;USD、EUR、HKD、CNY 到 0.01),取整方向跟随 side:收款向上、付款向下,零头始终对你有利。
查询参数
| 参数 | 必填 | 说明 |
|---|---|---|
base / quote |
是 | 同 GET /v1/rate,含别名 from / to |
amount |
是 | 标价币种金额,十进制字符串,必须 > 0。换算结果(payable、mid_payable)按结算币种最小单位取整后,连同小数位最多 28 位,超出时返回 400 bad_request |
strategy |
否 | 同 GET /v1/rate |
响应
| 字段 | 类型 | 说明 |
|---|---|---|
base / quote |
string | 货币对 |
amount |
string | 你传入的金额,十进制字符串 |
payable |
string | 结算金额。收款方(side=charge)是客户应付金额,向上取整;付款方(side=pay)是你应付出的金额,向下取整 |
rate |
string | 使用的最终汇率 |
mid_rate |
string | 市场中间价 |
mid_payable |
string | 按中间价计算的金额(四舍五入),用于对比 |
gain_vs_mid |
string | 对你有利的差额,越大越好。收款方:payable - mid_payable(多收的);付款方:mid_payable - payable(少付的) |
markup_bps |
int | 使用的点差 |
markup_source |
string | 点差来源,同 GET /v1/rate |
side |
string | charge / pay,同 GET /v1/rate |
chosen_provider |
string | 汇率来自哪个源(匿名代号) |
source_count |
int | 有效源数量 |
anchor_tier |
string | 基准档位 |
capped |
bool | 是否触及封顶线 |
floored |
bool | 是否触及保底线 |
GET /v1/convert只做换算,不锁价。真实下单请用POST /v1/quotes。
POST /v1/quotes
创建锁价报价单:汇率、点差和 payable 在 ttl_seconds 内保持不变,结算以 payable 为准。
请求体(JSON 对象,Content-Type: application/json,不超过 16 KiB)
| 字段 | 必填 | 说明 |
|---|---|---|
base / quote |
是 | 货币对。别名 from / to |
amount |
是 | 标价币种金额,必须 > 0。建议传十进制字符串,也接受 JSON number |
reference |
否 | 你自己的订单号(最多 128 个字符),原样保存并返回,便于对账 |
strategy |
否 | 汇率站在哪一边,同 GET /v1/rate |
请求体不是合法 JSON、不是 JSON 对象或字段类型不对时返回 400 bad_request。
响应(HTTP 201)
| 字段 | 类型 | 说明 |
|---|---|---|
quote_id |
string | 报价单 ID(32 位小写十六进制)。请保存,用于后续查询与对账 |
reference |
string | null | 原样返回你传入的订单号 |
base / quote |
string | 货币对 |
amount |
string | 标价币种金额 |
payable |
string | 结算金额,即锁定的值。过期前不会变化。取整方向跟随 side |
rate |
string | 锁定的最终汇率 |
raw_rate |
string | 加点差前的汇率 |
mid_rate |
string | 下单时的市场中间价,便于对账 |
markup_bps |
int | 创建时锁定的点差。之后在控制台修改点差不影响这张报价单 |
strategy |
string | 选价策略 |
side |
string | charge / pay,同 GET /v1/rate |
chosen_provider |
string | 汇率来自哪个源(匿名代号)—— 争议或对账时的凭据 |
source_count |
int | 当时的有效源数量 |
created_at / created_at_unix |
string / float | 创建时间 |
expires_at / expires_at_unix |
string / float | 过期时间。过期后用该 ID 查询返回 404 |
ttl_seconds |
int | 锁价时长(秒) |
报价单无法保存时返回 503 storage_unavailable,此时报价单不存在,请重试。
GET /v1/quotes/{quote_id}
取回报价单。字段与创建时返回的完全相同,另多一个:
| 字段 | 类型 | 说明 |
|---|---|---|
expired |
bool | 是否已过期。报价单一过期就会被删除,通常你会直接得到 404;只有在删除前的极短窗口内这个字段才可能为 true |
quote_id不是 32 位小写十六进制,或报价单不存在、已过期 → 404not_found- 503
storage_unavailable表示此刻无法查询,不代表报价单已过期。请重试
GET /v1/sources
当前为你提供汇率的数据源有哪些、各自有多新鲜。用来判断某个汇率可以信任到什么程度。
响应
| 字段 | 类型 | 说明 |
|---|---|---|
sources |
object[] | 当前启用的数据源 |
source_count |
int | 数据源数量 |
last_poll_at |
string | null | 最近一次抓取时间(ISO 8601 UTC) |
sources[] 每一项
| 字段 | 类型 | 说明 |
|---|---|---|
provider |
string | 匿名源代号,与 GET /v1/rate 的 sources[].provider 对应 |
label |
string | 数据源展示名 |
data_freq |
string | 该源自身数据的更新频率:realtime / hourly / daily |
last_fetch_at |
string | null | 我们最近一次从该源抓取的时间 |
last_fetch_age |
float | null | 距最近一次抓取过了多少秒 |
source_time |
string | null | 该源自称的数据时间。null 表示该源不提供 |
source_age_seconds |
float | null | 该源数据的年龄(秒) |
currencies |
int | 该源当前覆盖了多少个支持的币种 |
这两个时间含义完全不同。
last_fetch_at是我们拉取数据的时间,所以总是很新;source_time是数据源自己声称的数据时间。每日更新的源通常滞后 12–36 小时, 个别每日源在周末会超过 80 小时 —— 这是正常的。 只看last_fetch_at判断新鲜度会严重误判。
GET /health
服务健康检查,不需要 API key。供你的监控或负载均衡使用。
| 字段 | 类型 | 含义 |
|---|---|---|
status |
string | ok / degraded。只反映「此刻能不能出价」 |
sources_healthy |
int | 当前有新鲜可用数据的源数量 |
last_updated_at |
string | null | 最近一次抓到源数据的时间(ISO 8601 UTC) |
HTTP 状态:ok 时 200,degraded 时 503。
该接口刻意只返回一个健康信号,不透露内部抓取状态和上游错误细节。 需要逐个源的新鲜度请用
GET /v1/sources,或查看状态页。
GET /openapi.json
上述全部接口的 OpenAPI 3.1 文档,地址为 https://api.crestrate.com/openapi.json。不需要 API key,允许浏览器跨域读取,缓存 5 分钟。文档同时声明了两种鉴权方式(X-API-Key 与 Bearer),SDK 生成器可直接使用。
网站上的 https://crestrate.com/openapi.json 以 HTTP 302 重定向到上述地址。工具里请直接填写 API 地址。
错误响应
所有接口的错误格式一致:
| 字段 | 类型 | 说明 |
|---|---|---|
error |
string | 机器可读的错误码。请按它匹配,不要按 message |
message |
string | 给人看的英文说明,文案可能调整 |
currency |
string | 出错的币种代码(unsupported_currency、currency_not_available) |
supported |
string[] | 提供实时数据的币种(currency_not_available) |
retry_after |
number | 需等待的秒数(rate_limited) |
used / quota |
int | 本月已用请求数 / 月配额(quota_exceeded) |
upgrade_url |
string | 定价页的绝对地址(quota_exceeded) |
| HTTP | error |
含义 | 可以重试吗 |
|---|---|---|---|
| 400 | bad_request |
参数缺失或非法:缺 base/quote、缺 amount、amount ≤ 0、不是数字或过大、未知 strategy、请求体不是合法 JSON、reference 过长 |
否,先修正请求 |
| 400 | unsupported_currency |
无法识别的币种代码。带 currency |
否 |
| 401 | api_key_required |
没有带 API key | 否,请带 X-API-Key 或 Authorization: Bearer |
| 401 | invalid_api_key |
key 无效或已撤销 | 否 |
| 403 | account_disabled |
账号已被停用,请联系支持 | 否 |
| 403 | email_not_verified |
账号邮箱尚未验证 | 验证后可以 |
| 404 | not_found |
报价单不存在或已过期;路径不存在 | 否 |
| 413 | payload_too_large |
请求体超过 16 KiB | 否 |
| 422 | currency_not_available |
该币种暂时无法提供实时数据。带 currency 与 supported |
开放前不行 |
| 429 | rate_limited |
超过限速。带 Retry-After 头与 retry_after 字段 |
可以,等 Retry-After 之后 |
| 429 | quota_exceeded |
月配额已用完。带 used、quota、upgrade_url |
否,升级或等下个月 |
| 500 | internal_error |
服务端意外错误 | 可以,退避重试;持续出现请附 X-Request-Id 联系支持 |
| 503 | no_rate |
有效源不足,无法给出可信的汇率。message 列出各源被剔除的原因(只含匿名代号) |
可以,稍后重试;期间使用你自己的备用汇率 |
| 503 | storage_unavailable |
服务暂时不可用,未保存任何数据 | 可以,退避重试 |
示例:
{
"error": "currency_not_available",
"message": "Real-time data for GBP is temporarily unavailable. Supported: USD, JPY, EUR, HKD, CNY.",
"currency": "GBP",
"supported": ["USD", "JPY", "EUR", "HKD", "CNY"]
}
503 no_rate 是刻意的 —— 我们宁可不给价,也不给来源存疑的价。调用方应稍后重试,或回退到自己的兜底汇率。不要当成 0 处理。
最佳实践
用 strategy 选对边。 向客户收款用默认的 max,给卖家或供应商付款用 min,median 只用于记账。选错了,选价、点差和取整就都在替对方着想。
用十进制类型解析汇率,永远不要用浮点。 所有汇率和金额都是 JSON 字符串,正是为此。
按 IEEE-754 双精度解析,0.05117904 会丢精度,合计金额会慢慢漂移。
请用 Decimal / BigDecimal / decimal.js / bcmath。
收款前一定先锁价。 客户看到价格和实际付款之间有时间差,汇率在这段时间里会动。
POST /v1/quotes 把汇率、点差和金额冻结到 TTL 结束,并给你一个 quote_id 用于之后对账。
GET /v1/convert 只用于展示和估算 —— 不要用它下单。
rate_limited 值得重试,quota_exceeded 不值得。 前者是暂时的,按 Retry-After 退避后再试。
后者在本自然月内是硬性阻断,而且账号下所有 key 共同受限。请升级,或等下个月重置。
永远不要把 503 no_rate 当成 0。 它的意思是「有效源太少,我们不会给你一个站不住的价格」。
回退到你自己的兜底汇率,或暂停下单流程。不要乘以 0。
在你这边先校验币种。 使用暂时无法提供实时数据的币种的请求同样计入配额;调用前先对照支持列表检查。
在你这边做缓存。 汇率不会比我们最快的源变得更快。缓存 30–60 秒能大幅减少用量,精度几乎不受影响。
关注 capped、floored 和 anchor_tier。 capped: true 或 floored: true 表示市场在动而较慢的源还没跟上,我们把报价钳回了实时市场附近。
anchor_tier 退到 daily 或 all 表示最新鲜的源暂时不可用 —— 汇率仍然可用,只是不如平时新鲜。
监控按 error 与 excluded_code 匹配,不要按文案。 message 与 excluded_reason 是给人看的,措辞可能调整。
版本策略
当前为 v1,版本号是路径的一部分(/v1)。我们会新增字段而不另行通知,请做防御性解析,忽略不认识的键。
删除或改变现有字段的用途、修改字段类型、修改错误码的含义或 HTTP 状态,我们不会在少于 90 天通知期的情况下进行。 通知会发送到近期有调用的每位客户的账号邮箱。
支持
有疑问,或发现行为与文档不符?请发邮件至 [email protected],并附上该请求的 X-Request-Id。