> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nonce.app/llms.txt
> Use this file to discover all available pages before exploring further.

# 迁移到 API v2

> v1 与 v2 的接口对照、字段变化和迁移说明。

本迁移文档将帮助你理解如何从 Private API v1 迁移到 API v2。你也可以把下方的 prompt 交给你的 AI agent，让迁移过程更加顺畅！

<Prompt description="将项目中的 Nonce API v1 集成迁移到 API v2" actions={["copy"]}>
  将 \[客户端或模块] 中的 Nonce Private API v1 读取集成迁移到 Public API v2。未指定目标时，检查整个项目。

  参考资料：

  * 迁移指南：[https://docs.nonce.app/zh/api-guide/v2/migration](https://docs.nonce.app/zh/api-guide/v2/migration)
  * 兼容性说明：[https://docs.nonce.app/zh/api-guide/v2/migration-compatibility](https://docs.nonce.app/zh/api-guide/v2/migration-compatibility)
  * API Reference：[https://docs.nonce.app/api-reference/v2/workspaces/list-workspaces](https://docs.nonce.app/api-reference/v2/workspaces/list-workspaces)
  * OpenAPI 契约：[https://docs.nonce.app/api-reference/openapi-v2.json](https://docs.nonce.app/api-reference/openapi-v2.json)
    修改代码前，阅读指南、兼容性说明和可用的接口契约，核对现有代码实际使用的字段及行为。接口没有完整 Reference 时，可依据迁移指南中已明确说明的字段和行为处理；只有必需信息仍无法确认时才列为待解决项。网页无法读取时，在文档 URL 后加 .md 重试。字段疑问应先通过对应接口 Reference 或 OpenAPI 契约查证，不要直接交回开发者。所需资料仍不可用时，报告缺少的内容，停止依赖该资料的代码修改。

  检查 HTTP client、公共封装、代理层、配置、调用处和数据处理代码，搜索 /private-api/v1 及动态拼接路径，包括 /miner/latest 和 /miners/latest，找出全部 v1 调用。列出各调用的用途、筛选条件、分页方式及实际读取的响应字段；写入接口等本指南未覆盖的调用也应列为待解决项。

  按照文档转换接口和字段，保留原有功能。重点检查工作区与矿场范围、归档矿场、完整分页、MAC 精确匹配、旧版忽略的筛选条件，以及 last\_updated\_at.gt/lt 的严格边界。历史查询需要保留时区、显式粒度、左闭右开时间范围、单次查询跨度限制、结果顺序和 null 值。task batch 需要读取全部任务分页，并区分 unsuccessful\_count 与 failed\_count。指标单位保持不变。

  使用已有测试和样例验证受影响的功能，缺少覆盖时补充必要测试。根据实际调用覆盖空结果、多页、匹配条件和边界，以及 401/403/404 响应，不得把错误作为成功的空结果处理。运行项目相关检查，并说明未能执行的检查。不操作真实设备，不输出凭据，不执行发布。

  只使用文档明确说明的替代字段和接口，并记录使用的 beta 接口。必需字段、权限或业务含义没有已确认的替代方案时，列出受影响的功能，继续处理不依赖该问题的部分。不要删除功能、悄悄保留 v1 回退，或通过填充空值掩盖差异。

  最后重新搜索 v1 路径、公共基础地址及旧响应字段，将剩余匹配逐项归为非运行时代码或待解决的迁移问题。列出改动文件、已迁移调用、实际验证结果和未解决项。结论明确标为“已完成”或“未完成”。必需功能缺失、仍依赖 v1 调用、必要契约细节尚未确认或相关检查未通过时，标为“未完成”，不要写成“已完成，等待确认”。
</Prompt>

生成的代码仍需审核。

本文介绍 Private API v1 读取接口迁移到 Public API v2 时，接口路径、查询范围、分页和返回字段的主要变化。现有有效的 workspace API key 和 Bearer 认证方式可以继续使用；响应外层仍使用 `success`、`data` 和 `error`。

<Warning>
  Private API v1 是旧版接口，将在后续下线。v2 的 Workspace、分类统计和历史指标接口目前为 beta，后续可能有不兼容变更。
</Warning>

示例的 API 地址为 `https://api.nonce.app`。下表省略 v1 的 `/private-api/v1/{workspace_id}` 前缀；`/me` 的完整路径为 `/private-api/v1/me`。

| v1 调用                                                       | v2 接口                                         |
| ----------------------------------------------------------- | --------------------------------------------- |
| `GET /me`                                                   | [`ListWorkspaces`](#workspace)                |
| `GET /farms`                                                | [`ListFarms`](#矿场)                            |
| `GET /agents`                                               | [`ListAgents`](#agent)                        |
| `GET /farms/{farm_id}/miner/latest`（另有 `/miners/latest` 形式） | [`ListMiners`](#矿机)、[`SearchMiners`](#筛选)     |
| `POST /farms/{farm_id}/miners/search`                       | [`SearchMiners`](#筛选)                         |
| `GET /farms/{farm_id}/miners/stats`                         | [`QueryFarmMinerMetrics`](#分类统计)              |
| `GET /farms/{farm_id}/metrics/history`                      | [`QueryFarmMetrics`](#历史指标)                   |
| `GET /farms/{farm_id}/tasks/batches`                        | [`ListTaskBatches`](#task-batch)              |
| `POST /farms/{farm_id}/tasks/search`                        | [`SearchTaskBatches`](#task-batch)            |
| `GET /farms/{farm_id}/tasks/batches/{batch_id}`             | [`GetTaskBatch`、`ListTaskBatchTasks`](#详情与任务) |

## 认证

有效的 workspace API key 继续通过 `Authorization: Bearer <workspace_api_key>` 传入。v2 中，401 表示认证失败，403 表示权限不足，404 表示资源不存在或不在可访问范围内，例如超出密钥授权范围的矿场。这些错误不能作为空列表处理。

## 分页

列表使用 URL 查询参数分页，搜索使用 JSON 请求体分页。`page` 和 `page_size` 均可省略，默认分别为 1 和 20。历史指标改为按时间范围查询，不使用分页。

| 分页行为        | v1               | v2                   |
| ----------- | ---------------- | -------------------- |
| GET 每页数量    | `pageSize`       | `page_size`          |
| Search 每页数量 | `limit`          | `page_size`          |
| 默认每页数量      | 10               | 20                   |
| 最大每页数量      | 10,000           | 10,000               |
| 响应中的页面位置    | `limit`、`offset` | `page`、`page_size`   |
| 是否有下一页      | `hasNext`        | `page < total_pages` |
| 是否有上一页      | `hasPrevious`    | `page > 1`           |

分页信息位于 `pagination`，与 `success`、`data`、`error` 同级。

客户端从第 1 页开始读取，在 `page < total_pages` 时继续请求下一页；`total` 为 0 时结束。数据在读取期间可能变化，跨页结果不保证属于同一时刻。

旧 GET 接口未定义 `limit` 和 `offset`。使用过这两个参数的集成，需要检查原分页逻辑是否生效。

## Workspace

已有的 `workspace_id` 可以继续使用。原来通过 `/me` 获取 workspace 信息的集成，改用 `ListWorkspaces`：

```http theme={null}
GET /public-api/v2/workspaces
Authorization: Bearer <workspace_api_key>
```

`data` 改为无分页数组，按 `id` 选择目标 workspace。每项中的 `workspace_id`、`workspace_name`、`workspace_slug` 分别改为 `id`、`name`、`slug`。

使用 API key 时，列表包含密钥所属的 workspace（`relations` 含 `member`），以及通过有效授权可访问的 workspace（`relations` 含 `grantee`）。使用 OAuth 时，列表包含当前用户加入的 workspace。每项的 `permissions` 表示有效的 API 操作权限。

`ListFarms` 返回同一认证身份可以访问的矿场。`permissions` 不包含矿场 ID 列表。v2 目前没有接口提供 `/me/grants` 中完整的 `farm_ids` 和授权到期记录；依赖这些数据的集成，需要先确认数据获取方式，才能完成迁移。

## 矿场

v1：

```http theme={null}
GET /private-api/v1/{workspace_id}/farms?page=1&pageSize=100
```

v2：

```http theme={null}
GET /public-api/v2/workspaces/{workspace_id}/farms?page=1&page_size=100
```

v2 返回尚未删除的矿场，包括已归档的记录；排除 `archived: true` 后，可保持 v1 的查询范围。排序规则也已调整，相同页码不保证对应相同的记录。

## Agent

v1 在整个 workspace 范围内查询 Agent：

```http theme={null}
GET /private-api/v1/{workspace_id}/agents?page=1&pageSize=100
```

v2 改为按 farm 查询：

```http theme={null}
GET /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/agents?page=1&page_size=100
```

获取 workspace 范围内的全部 Agent，需要遍历可访问的矿场，并读取每个矿场的所有 Agent 页面。总数为所选矿场的 `total` 之和。

列表仍包含状态、版本、uptime 和更新时间，嵌套的 `farm` 对象改为 `farm_id`。主机信息不在列表摘要中，需要这些字段的集成可查阅[兼容性说明](/zh/api-guide/v2/migration-compatibility)。

## 矿机

`ListMiners` 返回无筛选列表，`SearchMiners` 用于筛选，两者返回相同的矿机摘要。

```http theme={null}
GET /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/miners?page=1&page_size=1000
```

| v1 字段      | v2                   |
| ---------- | -------------------- |
| `temp`     | `temperature`        |
| `stale`    | `status === "stale"` |
| 嵌套的 `farm` | `farm_id`            |

单位不变：`hashrate`、`expected_hashrate` 使用 H/s，`power` 使用 W，`efficiency` 使用 J/TH。

v2 摘要不包含旧完整对象的所有字段。依赖 `errors`、`hashboards`、`pools`、`psus`、`hashrate_24h` 或重启计数的集成，需要另外确认数据获取方式。[兼容性说明](/zh/api-guide/v2/migration-compatibility)列出了这些限制，仅修改字段名不足以完成迁移。

### 筛选

`SearchMiners` 通过 JSON 请求体接收筛选条件，不同字段之间采用 AND。例如，查询“online 且存在风扇或电源异常”的矿机：

```http theme={null}
POST /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/miners/search
Content-Type: application/json
```

```json theme={null}
{
  "status": { "in": ["online"] },
  "anomaly_flags": { "in": ["fan", "power"] },
  "page": 1,
  "page_size": 1000
}
```

“stale 或异常”这类跨字段 OR 条件需要分别查询，再按矿机 ID 合并去重。`anomaly_filters` 改为 `anomaly_flags.in`，`ip_ranges` 仍使用数组。

v2 的 `status` 只接受 `online` 和 `stale`，旧 `offline` 对应 `stale`。v1 中已被忽略的 `error`、`low_hashrate` 等健康状态不应转换成新的异常条件，否则会改变查询结果。详见[兼容性说明](/zh/api-guide/v2/migration-compatibility)。

精确 MAC 查询使用 `search.field = "mac"`，并通过 `search.value` 提供完整地址。由于字段搜索采用子串匹配，需要读取全部候选页，再忽略大小写比较完整 MAC，只统计精确匹配的记录。

`last_updated_at` 的 `gt` 和 `lt` 均为严格边界，返回结果不包含恰好等于边界的记录。

## 分类统计

`QueryFarmMinerMetrics`（beta）返回当前矿机分类和分布，请求从 GET 改为 POST，且不需要请求体。

v1：

```http theme={null}
GET /private-api/v1/{workspace_id}/farms/{farm_id}/miners/stats
```

v2：

```http theme={null}
POST /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/miner-metrics/query
```

| v1 响应                | v2 响应                        |
| -------------------- | ---------------------------- |
| `by_type`            | `classification`             |
| `by_abnormal_type`   | `anomaly_breakdown`          |
| `mining_mode`        | `mining_modes`               |
| `mining_mode[].mode` | `mining_modes[].mining_mode` |
| `miner_model`        | `miner_models`               |

v2 保留 `theo` 和 `total`，新增 `period` 表示数据观察时间，并在 `mining_modes` 的每项中增加 `firmwares` 分布。各分类可能重叠，总数以 `total` 为准；由于数据实时更新，不同请求的统计结果可能变化。

矿场不存在时，v1 可能返回空统计，v2 返回 404。查询历史趋势使用[历史指标](#历史指标)。

## 历史指标

`QueryFarmMetrics`（beta）用时间范围查询代替 v1 的分页查询，一次返回指定范围内的指标记录。以下示例查询 UTC 2026-09-01 的日级指标。

v1：

```http theme={null}
GET /private-api/v1/{workspace_id}/farms/{farm_id}/metrics/history?from_date=2026-09-01&to_date=2026-09-01&granularity=day
```

v2：

```http theme={null}
POST /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/metrics/query
Content-Type: application/json
```

```json theme={null}
{
  "from_time": "2026-09-01T00:00:00Z",
  "to_time": "2026-09-02T00:00:00Z",
  "granularity": "day"
}
```

查询包含 `from_time`，不包含 `to_time`。读取某一天的完整数据时，结束时间应设为次日零点。非 UTC 日期需要先按业务时区确定起止时间，再转换为 ISO 时间。

迁移时应明确传入 `granularity`：v1 默认 `day`，v2 默认 `hour`。

### 响应数据

历史记录从 `data` 移到 `data.snapshots`，`data` 同时返回查询时间范围。日级记录仍包含 `pool`、`agent`、`finance` 和 `electricity` 字段。

`snapshots` 按时间升序排列，没有数据的时间段也会返回记录，其指标值为 `null`。`null` 表示数据缺失，不等同于 0，因此“最近 N 个时间段”与“最近 N 条有数据的记录”需要分别处理。

记录不再包含 `id` 和 `workspace_id`，需要唯一标识时，可组合使用 farm、时间粒度和 `period`。`period` 表示该时间段的开始时间，使用 ISO 8601 字符串。

### 查询范围

单次查询的最大范围如下：

| 粒度      | 最大范围  |
| ------- | ----- |
| `10min` | 1 天   |
| `hour`  | 7 天   |
| `day`   | 90 天  |
| `week`  | 365 天 |

超出上限时，应按原业务时区将查询拆成连续、不重叠的时间段，各段边界与所选粒度对齐，返回记录按 `period` 合并。旧的 7 天 `10min` 查询或 60 天 `hour` 查询，也需要按新的范围上限拆分。

## task batch

列表使用 URL 查询参数，搜索使用 JSON 请求体。

```http theme={null}
GET /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/task-batches?task_name=miner.system.reboot&page=1&page_size=50
POST /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/task-batches/search
```

```json theme={null}
{
  "task_name": { "eq": "miner.system.reboot" },
  "page": 1,
  "page_size": 50
}
```

`batch_id` 改为 `id`。列表中的 `failed_count` 改为 `unsuccessful_count`，仍表示失败、超时和取消的合计。

### 详情与任务

v1 的 task batch 详情内嵌 `tasks`；v2 改为由 `GetTaskBatch` 返回摘要，通过 `ListTaskBatchTasks` 单独分页读取任务。

```http theme={null}
GET /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/task-batches/{task_batch_id}
GET /public-api/v2/workspaces/{workspace_id}/farms/{farm_id}/task-batches/{task_batch_id}/tasks?page=1&page_size=100
```

<Warning>
  详情响应中的 `failed_count` 只统计执行失败，与列表中的 `unsuccessful_count` 含义不同。
</Warning>
