总览
接入概览
接入前先确认
- 先在控制台创建接口密钥,再调用 /v1/*;不要把明文接口密钥直接硬编码进浏览器前端。
- 免费版工作区最多只能保留 1 个有效接口密钥;如果你要轮换密钥,需要先撤销旧密钥,或者升级到付费方案。
- 所有公开 POST 接口都建议带上 Idempotency-Key,方便你做重试、消息队列消费和防重放。
- 如果你只想先打通一个最小闭环,推荐顺序是 airports/search -> flights/search -> account/usage。
鉴权与幂等
- 公开业务接口统一挂在 /v1 下,调用时必须携带 X-API-Key。
- 所有公开 POST 接口都建议附带 Idempotency-Key,服务端会按 tenant、endpoint 与请求哈希做幂等回放。
- 成功响应统一返回 request_id、data、meta、error 四个顶层字段。
- 限流由密钥网关实时校验;命中后会返回 429,并带 Retry-After 响应头。
- 额度相关接口和计费型请求还会返回 X-Flight-Scout-Quota-* 响应头,便于客户端直接读取剩余额度与周期结束时间。
推荐调用链路
- 机场输入联想:先调用 /v1/airports/search 获取 IATA 机场码。
- 标准实时查询:使用 /v1/flights/search 或 /v1/flights/calendar。
- 隐藏城市轻量预览:用 /v1/flights/hidden-city/search,适合快速判断是否值得展开。
- 隐藏城市完整扫描:先 POST /v1/flights/hidden-city/jobs,再轮询 /v1/jobs/{job_id}。
- 用量分析:通过 /v1/account/usage 拉取按计量项聚合后的请求量与点数。
计量权重
- flight.search.request = 1 点调用额度
- flight.calendar.request = 3 点调用额度
- flight.hidden_city.job.request = 10 点调用额度
- flight.hidden_city.sync.request = 15 点调用额度
- GET /v1/airports/search、GET /v1/jobs/{job_id}、GET /v1/account/usage 不做显式计费。
常见错误
- 401 unauthorized:缺少或错误的 X-API-Key。
- 404 not_found:常见于轮询不存在的 job_id。
- 422 validation_error:请求参数缺失、日期格式错误或枚举值不合法。
- 409 conflict:常见于复用同一个 Idempotency-Key 但请求体不同。
- 429 rate_limited:当前密钥命中限流,响应头会带 Retry-After。
- 402 quota_exceeded:当前请求会超出套餐包含额度,可从 meta.remaining_units、meta.cycle_ends_at 和 X-Flight-Scout-Quota-* 获取额度上下文。
- 503 provider_disabled:某个上游查询节点暂时不可用,可稍后重试或切换查询条件。
统一响应结构
{
"request_id": "0d2a52d1-9387-44e9-b690-7f0c14c527ce",
"data": {
"search": {
"origin": "SHA",
"destination": "HND",
"date": "2026-06-12"
},
"offers": [
{
"price": {
"amount": 1280,
"currency": "CNY"
},
"stops": 0,
"duration_minutes": 175,
"route_summary": "MU539 SHA -> HND"
}
],
"booking_summary_attached": 0
},
"meta": {
"cache_hit": false
},
"error": null
}
快速开始
快速开始
如果你的站点和接口已经通过反向代理挂到同一域名,直接把 BASE_URL 设置成当前域名即可。前端浏览器场景建议通过你自己的服务端代理转发接口密钥,而不是在客户端硬编码密钥。
如果你当前是免费版工作区,请把它当作单密钥沙盒来用。控制台最多只保留 1 个有效接口密钥;轮换密钥时先撤销旧密钥,或者升级到付费方案后再做多环境并行接入。
curl
export BASE_URL="https://your-domain.com"
export API_KEY="fs_live_your_api_key"
curl -X POST "$BASE_URL/v1/flights/search" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"origin": "SHA",
"destination": "HND",
"date": "2026-06-12",
"passengers": 1,
"cabin_class": "economy",
"sort_by": "best"
}'
fetch
const baseUrl = "https://your-domain.com";
const apiKey = process.env.FLIGHT_SCOUT_API_KEY;
const response = await fetch(`${baseUrl}/v1/flights/search`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "SHA",
destination: "HND",
date: "2026-06-12",
passengers: 1,
cabin_class: "economy",
sort_by: "best",
}),
});
const payload = await response.json();
console.log(payload.data.offers);
公开接口公开数据接口
以下接口全部基于当前后端 /v1 路由整理,并按真实返回结构、默认值、计量规则与调用方式展示。
POST/v1/flights/search
标准航班搜索
X-API-Key1 点调用额度
标准同步搜索接口。服务端会把航班结果归一化成 offers 列表,按 `sort_by` 排序后返回当前搜索窗口里的全部报价,适合实时搜索、榜单排序与业务落地页展示。
请求字段
- origin / destination3 位 IATA 机场码,服务端会自动转成大写。
- date出发日期,格式 YYYY-MM-DD。
- return_date往返返程日期,可留空。
- passengers1 到 9,默认 1。
- cabin_classeconomy、business、first,默认 economy。
- sort_bybest、price、fastest、departure,默认 best。
- with_booking_summary是否在结果中附带订票摘要。
- booking_summary_limit0 到 3,仅在开启订票摘要时有意义。
返回重点
- data.search标准化后的查询上下文。
- data.offers报价数组,含价格、航段、经停数、时长和可选订票摘要。
- data.booking_summary_attached本次实际附加的订票摘要数量。
- meta.cache_hit是否命中缓存。
使用建议
- 适合前台实时查询与轻量聚合服务。
- `booking_summary_limit` 只限制附加订票摘要的数量,不会截断 `data.offers` 主报价列表。
- 如果你会做重试或队列重放,建议总是携带 Idempotency-Key。
curl
curl -X POST "$BASE_URL/v1/flights/search" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"origin": "LHR",
"destination": "PEK",
"date": "2026-05-01",
"passengers": 1,
"cabin_class": "economy",
"sort_by": "best"
}'
fetch
const res = await fetch(`${baseUrl}/v1/flights/search`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "LHR",
destination: "PEK",
date: "2026-05-01",
passengers: 1,
cabin_class: "economy",
sort_by: "best",
}),
});
const payload = await res.json();
console.log(payload.data.offers);
POST/v1/flights/calendar
价格日历搜索
X-API-Key3 点调用额度
按日期范围搜索价格日历并挑选候选出发日,适合做低价日历、灵活日期推荐和价格趋势看板。
请求字段
- origin / destination3 位 IATA 机场码,服务端自动转大写。
- date_start / date_end搜索窗口起止日期。
- locale日历搜索的本地化参数,默认 zh-HK。
- currency返回货币,默认 CNY。
- window_days单次窗口跨度,1 到 90,默认 30。
- max_pages最大抓取页数,1 到 10,默认 3。
- timeout日历搜索超时秒数,1 到 60,默认 12。
返回重点
- data.calendar_query本次日历查询的标准化上下文。
- data.calendar标准化后的日历结果主体,包含最低价日期与价格排行。
- data.chosen_date服务端选出的推荐日期,可为 null。
- meta.cache_hit是否命中缓存。
使用建议
- 返回里的 calendar 已做平台标准化,适合前端自行做热力图或价格带渲染。
- 如果你最终仍要查具体报价,通常会在 chosen_date 上再调用 flights/search。
curl
curl -X POST "$BASE_URL/v1/flights/calendar" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"origin": "PVG",
"destination": "CDG",
"date_start": "2026-07-03",
"date_end": "2026-07-15",
"passengers": 1,
"locale": "zh-HK",
"currency": "CNY",
"window_days": 30
}'
fetch
const res = await fetch(`${baseUrl}/v1/flights/calendar`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "PVG",
destination: "CDG",
date_start: "2026-07-03",
date_end: "2026-07-15",
passengers: 1,
locale: "zh-HK",
currency: "CNY",
window_days: 30,
}),
});
const payload = await res.json();
console.log(payload.data.chosen_date, payload.data.calendar);
POST/v1/flights/hidden-city/search
隐藏城市同步搜索
X-API-Key15 点调用额度
低延迟的同步隐藏城市查询,适合做快速预览和决策判断。
请求字段
- origin / destination / date目标航线与出发日期。
- max_polls查询轮询次数,1 到 4。
- max_destinations同步扫描要探索的延伸目的地数量上限,1 到 10。
- min_savings最小节省金额过滤。
返回重点
- data.target原始目标航线摘要。
- data.direct_reference.price目标航线的参考价。
- data.direct_reference.selection_mode参考价选择方式:`direct_lowest`、`one_stop_fallback`、`lowest_available_fallback`、`candidate_pool_fallback`、`unavailable`。
- data.direct_reference.direct_available / one_stop_available目标航线是否存在直飞、是否存在 1 次中转。
- data.direct_reference.stops最终选中的参考航班经停数。
- data.candidates隐藏城市候选报价,包含 savings、航段、时长与隐藏城市说明。
- data.hidden_city_count识别出的隐藏城市候选数量。
使用建议
- 服务端会关闭 `booking_summary`,并在 30 秒内超时返回。
- 轻量版适合快速预览和同步场景。
- 服务端会返回当前扫描范围内的全部候选,不接受 `max_candidates`。
- 候选会按 savings 降序、price 升序排序,但不会按城市或行程去重。
- 如果 `selection_mode` 不是 `direct_lowest`,就表示参考价不是直飞;例如 `one_stop_fallback` 代表目标航线没有直飞,只找到了 1 次中转参考价。
- 如果你需要更完整的候选集合,请改用异步 job 版本。
curl
curl -X POST "$BASE_URL/v1/flights/hidden-city/search" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"origin": "LAX",
"destination": "JFK",
"date": "2026-09-12",
"min_savings": 200
}'
fetch
const res = await fetch(`${baseUrl}/v1/flights/hidden-city/search`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "LAX",
destination: "JFK",
date: "2026-09-12",
min_savings: 200,
}),
});
const payload = await res.json();
console.log(payload.data.candidates);
POST/v1/flights/hidden-city/jobs
隐藏城市异步任务
X-API-Key10 点调用额度
完整的隐藏城市异步扫描入口。请求会进入后台队列,由服务端在后台完成更重的组合搜索。
请求字段
- origin / destination / date目标航线与出发日期。
- max_destinations异步版本上限为 10。
- with_booking_summary异步版本允许附带订票摘要。
- booking_summary_limit0 到 3,仅在附带订票摘要时生效。
返回重点
- data.job_id任务主键,用于后续轮询。
- data.status创建时固定为 queued。
- data.status_url轮询地址,格式为 /v1/jobs/{job_id}。
- meta.queued始终为 true,表示任务已入队。
使用建议
- 该接口返回 HTTP 202。
- 服务端会返回当前扫描范围内的全部候选,不接受 `max_candidates`。
- 候选会按 savings 降序、price 升序排序,但不会按城市或行程去重。
- 推荐在客户端保存 job_id,并用指数退避轮询 /v1/jobs/{job_id}。
curl
curl -X POST "$BASE_URL/v1/flights/hidden-city/jobs" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"origin": "LAX",
"destination": "JFK",
"date": "2026-09-12",
"max_destinations": 8,
"with_booking_summary": true,
"booking_summary_limit": 2
}'
fetch
const enqueue = await fetch(`${baseUrl}/v1/flights/hidden-city/jobs`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "LAX",
destination: "JFK",
date: "2026-09-12",
max_destinations: 8,
with_booking_summary: true,
booking_summary_limit: 2,
}),
});
const payload = await enqueue.json();
console.log(payload.data.job_id, payload.data.status_url);
GET/v1/jobs/{job_id}
异步任务状态查询
X-API-Key不计费
轮询隐藏城市异步任务的执行状态。适合与 job 创建接口配合,获取最终结果、错误信息与过期时间。
路径与语义
- job_id由 /v1/flights/hidden-city/jobs 返回的任务主键。
- status可能为 queued、running、succeeded、failed、expired。
返回重点
- data.result任务成功后写入的响应载荷;失败时通常为空。
- data.error失败原因或错误信息。
- data.created_at / started_at / finished_at / expires_at任务生命周期时间戳。
- data.status当前任务状态。
使用建议
- 该接口不计入调用额度。
- 任务一旦过期,状态会被服务端标记为 expired。
curl
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/v1/jobs/6c7b2e5d-b0e8-4b6e-9d07-6fa232e9c4a5"
fetch
const res = await fetch(`${baseUrl}/v1/jobs/${jobId}`, {
headers: {
"X-API-Key": apiKey,
},
});
const payload = await res.json();
console.log(payload.data.status, payload.data.result);
GET/v1/airports/search
机场搜索联想
X-API-Key不计费
机场与城市联想接口。通常用在搜索框补全阶段,帮助用户拿到标准 IATA 码后再发起正式搜索。
查询参数
- q检索关键字,长度 2 到 100。
- locale本地化语言,默认 zh-CN。
返回重点
- data.query原始查询词。
- data.items机场数组,每项包含 code、name、city、country。
- meta.cache_hit是否命中缓存。
使用建议
- 该接口同样需要接口密钥,但不做显式计费。
- 建议前端做 250ms 左右输入防抖。
curl
curl -G "$BASE_URL/v1/airports/search" \
-H "X-API-Key: $API_KEY" \
--data-urlencode "q=shanghai" \
--data-urlencode "locale=zh-CN"
fetch
const params = new URLSearchParams({ q: "shanghai", locale: "zh-CN" });
const res = await fetch(`${baseUrl}/v1/airports/search?${params.toString()}`, {
headers: {
"X-API-Key": apiKey,
},
});
const payload = await res.json();
console.log(payload.data.items);
GET/v1/account/usage
账号用量汇总
X-API-Key不计费
查询当前工作区的用量汇总结果。服务端按 meter_name 聚合请求次数和计费点数,适合控制台、账单预估与告警系统。
查询参数
- period支持 all、day、month,默认 all。
返回重点
- data.tenant_id当前租户 ID。
- data.total_requests聚合后的总请求次数。
- data.total_units聚合后的总计费单位。
- data.meters按 meter_name 聚合的明细数组,含 count 与 units。
- data.quota.used_units当前额度周期内已消耗的总点数。
- data.quota.remaining_units当前额度周期剩余点数;支持超额计费的套餐会在超额后返回 0。
- data.quota.window_started_at / window_ends_at当前额度周期起止时间。
- data.quota.statuswithin_limit、exhausted、overage 或 tracked。
使用建议
- 该接口不会额外增加用量。
- period=month 使用最近 30 天窗口,不是自然月。
- quota 字段表示当前额度周期,不受 period 参数影响。
- 服务端也会返回 X-Flight-Scout-Quota-* 响应头,方便 CLI、网关和自动化任务直接读取。
curl
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/v1/account/usage?period=month"
fetch
const res = await fetch(`${baseUrl}/v1/account/usage?period=month`, {
headers: {
"X-API-Key": apiKey,
},
});
const payload = await res.json();
console.log(payload.data.total_units, payload.data.quota.remaining_units, payload.data.meters);