# DataGate Public API

本文档只描述 `https://feed.batx.ai` 的公开接口契约。内部 Cell 拓扑、上游连接、
缓存、部署和运维信息不属于公开 API 文档。

交互式调试与机器可读契约：

- Swagger：`GET /docs/swagger`
- OpenAPI 3.1：`GET /docs/openapi.json`
- Postman：`GET /docs/postman.zip`

## 认证

除 `/livez`、`/healthz` 和文档资源外，请求必须携带已签发的 Feed API key：

```http
X-API-Key: <key>
```

也可以使用等价的 Bearer 形式：

```http
Authorization: Bearer <key>
```

所有现有 Feed API key 默认可访问新增接口。WebSocket 推荐先调用
`POST /api/ws-ticket` 获取一次性 ticket。

## 通用约定

- Unix 时间戳默认使用 epoch milliseconds。
- 市场时间响应同时提供 IANA `timezone`。
- 表示瞬时的字符串使用带 `Z` 或 UTC offset 的 RFC 3339。
- 日期业务值使用 `YYYY-MM-DD`。
- BATX workspace 成功响应使用 `{"ok":true,"data":...}`。
- 失败响应使用 `{"ok":false,"error":"ERROR_CODE","message":"..."}`。
- `401` 表示 API key 无效或缺失；`400/422` 表示参数错误；`502/503` 表示数据源暂时不可用。

## System 与 Feed

| 方法 | 路径 | 参数 | 响应 |
|---|---|---|---|
| GET | `/livez` | - | 进程存活状态 |
| GET | `/healthz` | - | 公开 readiness 状态 |
| GET | `/api/status` | - | 已认证的服务状态 |
| GET | `/api/data-health` | - | 已认证的数据分区、持久化与发布进度 |
| POST | `/api/ws-ticket` | 仅精确 `batx-market-ticket-request/v1` object opt in；其他 body 保持 legacy | 一次性 legacy 或 audience-bound BATX market ticket |
| GET | `/api/universe` | `market,status,streamable,q,cursor,limit` | 标的目录分页 |
| GET | `/api/symbols` | - | 标的与订阅容量摘要 |
| GET | `/v1/symbols?profile=batx-symbol-catalog/v1` | `cursor,limit,catalog_revision` | Workspace 使用的 BATX canonical 标的目录快照 |
| GET | `/api/snapshot` | `symbols` | 最新 order/trade 快照 |
| GET | `/api/monitor` | - | 脱敏连接与流量统计；部署可使用独立 monitor key |

### `GET /api/data-health`

使用任一现有 Feed API key 查询逻辑数据分区的可用性和持久化进度。接口始终返回
HTTP 200；整体或单分区异常由顶层 `ok`、`feed.reasons` 和
`partitions[].status` 表达。响应不包含文件路径、凭据或网络地址，并带
`Cache-Control: no-store`。

顶层 `summary` 汇总已配置/已连接分区、Dataset/range 数量以及待完成的本地持久化和
交付批次。每个 `partitions[]` 包含：

- `partition_id`、`kind`、IANA `timezone`、`connected` 和 `status`；
- `datasets[]` 的当前 `data_version`、覆盖起止 epoch-ms、覆盖分区数、gap 数和更新时间；
- `ranges` 的标的数、周期列表、覆盖起止 epoch-ms；
- `persistence` 的待完成批次、启动后完成批次/事件数、最后完成时间和错误；
- `projection` 的 Published Dataset 数、覆盖分区数和最后发布时间；
- `pull` 的已配置 source 数、失败数、运行状态及逐 source 最近进度。

`status` 取值为 `healthy`、`catching_up`、`degraded`、`backpressured`、
`unavailable` 或 `disconnected`。所有 `*_ms` 字段均为 epoch milliseconds；配套
字符串为带 `Z` 或 UTC offset 的 RFC 3339。分区未连接或进度 RPC 不可用时，
`persistence.available=false`，未知计数返回 `null`，不会伪装成零积压。

```http
GET /api/data-health
X-API-Key: <key>
```

```json
{
  "ok": true,
  "generated_at_ms": 1788318000000,
  "generated_at": "2026-09-02T03:00:00Z",
  "timezone": "Etc/UTC",
  "time_unit": "ms",
  "summary": {
    "configured_partitions": 5,
    "connected_partitions": 5,
    "healthy_partitions": 4,
    "catching_up_partitions": 1,
    "dataset_count": 15,
    "range_count": 12000,
    "pending_local_batches": 0,
    "pending_delivery_batches": 240
  },
  "partitions": [
    {
      "partition_id": "us",
      "timezone": "America/New_York",
      "connected": true,
      "status": "catching_up",
      "persistence": {
        "mode": "realtime",
        "pending_local_batches": 0,
        "pending_delivery_batches": 240,
        "backpressured": false,
        "completed_batches_since_start": 12500,
        "completed_events_since_start": 820000,
        "last_completed_at_ms": 1788317999000,
        "last_completed_at": "2026-09-02T02:59:59Z",
        "last_error": null
      }
    }
  ]
}
```

`GET /api/universe` 中的名称字段保留各自语义：`name` 是 provider 原始名称，
`display_name` 是同语种的清洗展示名，`display_chinese_name` 是已校验的中文展示名。
中文 UI 应使用 `display_chinese_name → display_name → name → symbol` 的回退顺序，
不应把原始 `name` 视为中文名。

### `GET /v1/symbols?profile=batx-symbol-catalog/v1`

这是给 Workspace 后端读取的紧凑目录 read model，直接投影当前 Feed Universe，包含
Feed 已验证的 BATX canonical、Binance crypto 及已登记的指数 alias；它不等同于
provider 级 D2 canonical catalog。接口使用同一 Feed API key，但响应是原始
`batx-symbol-catalog/v1` object，不包裹 Workspace `ok/data` envelope。

响应的 `revision` 绑定完整有序集合；后续分页必须原样传回首屏的
`catalog_revision`，不匹配返回 `409`。`catalog_market` 是 Workspace 分类，
`catalog_normalizer` 仅在该市场需按既有 BATX 规则解释时出现。名称、关键词、时区、
交易所与 MIC 均为可选 enrichment，不能据此重建 identity。

## BATX workspace

| 方法 | 路径 | 参数或 JSON body | 响应 |
|---|---|---|---|
| GET | `/api/workspace/ohlcv` | `symbol,tf,n,before,after,fields,date,window,horizon` | K 线窗口 |
| POST | `/api/workspace/quotes` | `{"symbols":[...],"fields":"core"}` | 批量行情快照 |
| POST | `/api/workspace/klines_meta` | `{"symbols":[...]}` | 可用周期和时间范围 |
| POST | `/api/workspace/ohlcv_batch` | `{"reqs":[...]}` | 最多 8 个 OHLCV 请求 |
| GET | `/api/workspace/fundamentals` | `symbol,market,periods` | 财务卡片、股份、公司图片 URL |
| GET | `/api/workspace/company_profile` | `symbol,market` | 完整公司资料及 Logo/Icon URL |
| GET | `/api/workspace/market_cap` | `symbol,market` | 最新市值（亿元） |
| GET | `/api/workspace/financial_catalog` | - | 支持的公司/金融数据源 |
| GET | `/api/workspace/financial_records/{endpoint}` | `symbol,market,period_type,period_date,item_id,limit` | 原始公司/金融记录 |
| GET | `/api/workspace/infoway_financials` | `symbol,market` | 季度序列及公司图片 URL |
| GET | `/api/workspace/refinitiv_financials` | `symbol,market` | 上一接口的兼容别名 |

`POST /api/workspace/quotes` 的每个可用报价包含 `name`，该字段是服务端已解析的
展示名，回退顺序为 `display_chinese_name → display_name → name`。例如目录中
`600519_SH` 同时存在 `name: "Moutai"` 和 `display_chinese_name: "贵州茅台"` 时，
报价返回 `name: "贵州茅台"`。
Cell source 模式由 owning Cell 投影 symbol reference，并直接读取其最近日线计算
`prev_close`；Feed 不要求已有本地 reference/market 缓存。`klines_meta` 同样读取 owning
Cell 的持久化 coverage，meta 请求本身不会回源行情 provider。

OHLCV 响应使用 `time_contract:"raw-source-d-v1"`：整数 `rows[].d` 保留 provider
原始 epoch-ms instant；整数 `rows[].ts` 是交易所当地墙上时间编码到无时区 epoch 轴的
排序/分页游标，日线为 `trading_day` 的 UTC 零点；全市场必发 `rows[].trading_day`，
并提供 instrument IANA `timezone`。crypto 使用 `Asia/Shanghai`。`rows[].time` 是
`d` 在该时区下的 RFC 3339 兼容表示；`rows[].trading_date` 是保留的兼容别名，
与 `trading_day` 始终同值。K 线元数据通过
`native_tfs` / `effective_tfs` 区分原生与可派生周期。
未带 `before`、`after` 或 `date` 的 OHLCV 最近窗直接使用请求 `tf` 对应的
Infoway 原生 K 线，不使用其他周期或报价重算 OHLCV；未结束周期可带
`forming:true`。
BATX Binance symbol（例如 `BTC_USDT_BINANCE`）由 Workspace 映射到 catalog 中
现有的 Infoway crypto canonical，适用于 OHLCV、K 线元数据和批量报价；调用方继续
使用既有 BATX symbol。

详细的 BATX 请求和响应示例见 [BATX API](batx-integration.md)。

## Company profile

### `GET /api/workspace/company_profile`

查询参数：

| 参数 | 类型 | 必填 | 说明 |
|---|---|---:|---|
| `symbol` | string | 是 | BATX canonical，例如 `AAPL_NASDAQ`、`0700_HK` |
| `market` | string | 否 | 市场提示，例如 `US`、`HK`、`CN` |

请求：

```http
GET /api/workspace/company_profile?symbol=AAPL_NASDAQ&market=US
X-API-Key: <key>
```

响应：

```json
{
  "ok": true,
  "data": {
    "symbol": "AAPL_NASDAQ",
    "provider_symbol": "AAPL.US",
    "market": "us",
    "provider": "infoway",
    "logo_url": "https://assets.example/AAPL-logo.png",
    "icon_url": "https://assets.example/AAPL-icon.png",
    "company": {
      "basic_info": {
        "name": "Apple Inc.",
        "logo": "https://assets.example/AAPL-logo.png",
        "icon": "https://assets.example/AAPL-icon.png"
      },
      "company_profile": {
        "description": "Company description supplied by Infoway"
      }
    }
  }
}
```

`company` 是 Infoway 公司资料对象，未知或新增字段会原样保留。`logo_url` 和
`icon_url` 是便于下游直接下载的顶层字段；DataGate 不代理图片。上游未提供图片时
字段为 `null`。

同一份公司资料还可通过下面的原始记录接口获取：

```http
GET /api/workspace/financial_records/company?symbol=AAPL_NASDAQ
```

`/api/workspace/fundamentals`、`/api/workspace/infoway_financials` 和
`/api/workspace/refinitiv_financials` 也包含可空的 `logo_url` / `icon_url`。

## Cell V2 public

| 方法 | 路径 | 说明 |
|---|---|---|
| GET/POST | `/api/cell/v2/llm/catalog` | 查询 LLM 可用 Dataset 和 schema |
| POST | `/api/cell/v2/llm/query` | 固定数据版本的只读 SQL 查询 |
| POST | `/api/cell/v2/news/query` | 按时间窗分页读取规范化新闻历史 |
| GET | `/api/cell/v2/discovery/datasets` | 查询公开 Dataset 目录 |
| POST | `/api/cell/v2/analytics/catalog` | 查询 typed analytics schema |
| POST | `/api/cell/v2/analytics/query` | 类型化参数的只读分析查询 |
| WS | `/api/cell/v2/ws` | Kline、market、news、Dataset 版本通知订阅 |
| WS | `/api/cell/v2/market/ws` | BATX canonical 行情 subscribe/ACK、status、sequence、gap/replay |

请求和帧格式见 [Cell V2 Public API](cell-v2-api.md)。公开 Cell V2 路由统一使用
`/api/cell/v2/` 前缀。typed analytics Dataset binding 可选字符串等值
`scan.filters`，用于在 relation 层限定 symbol 等稳定键。

## WebSocket

- Legacy Feed：`wss://feed.batx.ai/ws?ticket=<ticket>`
- Cell V2：`wss://feed.batx.ai/api/cell/v2/ws?ticket=<ticket>`
- BATX market v1：`wss://feed.batx.ai/api/cell/v2/market/ws?ticket=<typed-ticket>`

完整 control frame 和事件格式见 [WebSocket API](feed-websocket.md)。
