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

# 日志查询

> 按时间与类型分页拉取调用、消费、充值等业务日志

## 简介

通过开放接口拉取当前凭证可见范围内的业务日志，覆盖消费、充值、错误、退款、管理与测试金等类型，适合对账、排障与用量统计。

<CardGroup cols={2}>
  <Card title="单次最多 31 天" icon="calendar">
    `startTime` / `endTime` 跨度不可超过 31 天；时间格式统一为 `yyyy-MM-dd HH:mm:ss`。
  </Card>

  <Card title="分页默认值" icon="list">
    默认 `page=1`、`pageSize=30`；`pageSize` 最大 1000。
  </Card>
</CardGroup>

## 接口

| 项   | 值                                                            |
| --- | ------------------------------------------------------------ |
| 方法  | `GET`                                                        |
| URL | `https://client.tennda.ai/prod-api/api/logs/openLog`         |
| 鉴权头 | `Authorization`                                              |
| 语言头 | `Accept-Language`（`zh-CN` / `en-US`，影响 `billingProcessText`） |

## 鉴权

请求头支持以下两种写法：

```http theme={null}
Authorization: Bearer sk-your_api_key
Authorization: sk-your_api_key
```

| 凭证类型                                                   | 可见范围        | `tokenName`            |
| ------------------------------------------------------ | ----------- | ---------------------- |
| [系统访问令牌](https://client.tennda.ai/#/profile?tab=token) | 该用户全部相关日志   | 可传，模糊匹配                |
| [API Key](/cn/interface-module/token-management)       | 仅当前 Key 的日志 | 忽略入参，服务端强制按当前 Key 精确过滤 |

<Warning>
  完整 Key 勿写入 URL、前端、日志或工单。
</Warning>

## 请求参数

### 分页

<ParamField query="page" type="integer" default="1">
  页码；`≤ 0` 时按 `1` 处理
</ParamField>

<ParamField query="pageSize" type="integer" default="30">
  每页条数；`≤ 0` 时按 `30` 处理，上限 `1000`
</ParamField>

### 筛选

<ParamField query="tokenName" type="string">
  API Key 名称。仅系统访问令牌鉴权时生效（模糊匹配）；API Key 鉴权时不可用
</ParamField>

<ParamField query="modelName" type="string">
  模型名称，精确匹配；多个模型用英文逗号分隔
</ParamField>

<ParamField query="requestId" type="string">
  请求 ID，精确匹配
</ParamField>

<ParamField query="types" type="string">
  日志类型，多个值用英文逗号分隔，例如 `2,5`
</ParamField>

| `types` 取值 | 含义  |
| ---------: | --- |
|        `1` | 充值  |
|        `2` | 消费  |
|        `3` | 管理  |
|        `5` | 错误  |
|        `6` | 退款  |
|        `8` | 测试金 |

### 时间

<ParamField query="startTime" type="string">
  开始时间，`yyyy-MM-dd HH:mm:ss`，含边界
</ParamField>

<ParamField query="endTime" type="string">
  结束时间，`yyyy-MM-dd HH:mm:ss`，含边界
</ParamField>

<Note>
  `Accept-Language` 只影响返回字段 `billingProcessText` 的文案语言：`zh-CN` / 未传 → 中文，`en-US` → 英文。
</Note>

## 请求示例

<Tabs>
  <Tab title="curl">
    ```bash theme={null}
    curl --get 'https://client.tennda.ai/prod-api/api/logs/openLog' \
      --header 'Authorization: Bearer your_api_key' \
      --header 'Accept-Language: zh-CN' \
      --data-urlencode 'page=1' \
      --data-urlencode 'pageSize=30' \
      --data-urlencode 'startTime=2026-07-01 00:00:00' \
      --data-urlencode 'endTime=2026-07-21 23:59:59' \
      --data-urlencode 'types=2,5'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const params = new URLSearchParams({
      page: '1',
      pageSize: '30',
      startTime: '2026-07-01 00:00:00',
      endTime: '2026-07-21 23:59:59',
      types: '2,5',
    });

    const response = await fetch(
      `https://client.tennda.ai/prod-api/api/logs/openLog?${params}`,
      {
        method: 'GET',
        headers: {
          Authorization: 'Bearer your_api_key',
          'Accept-Language': 'zh-CN',
        },
      },
    );

    const result = await response.json();
    if (result.code !== 200) {
      throw new Error(result.msg);
    }

    console.log(result.data.total, result.data.rows);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    url = "https://client.tennda.ai/prod-api/api/logs/openLog"
    headers = {
        "Authorization": "Bearer your_api_key",
        "Accept-Language": "zh-CN",
    }
    params = {
        "page": 1,
        "pageSize": 30,
        "startTime": "2026-07-01 00:00:00",
        "endTime": "2026-07-21 23:59:59",
        "types": "2,5",
    }

    response = requests.get(url, headers=headers, params=params, timeout=30)
    response.raise_for_status()
    result = response.json()

    if result.get("code") != 200:
        raise RuntimeError(result.get("msg"))

    print("总记录数：", result["data"]["total"])
    for item in result["data"]["rows"]:
        print(item["requestId"], item["modelName"], item["quotaDollar"])
    ```
  </Tab>
</Tabs>

## 成功响应

```json theme={null}
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "id": "7485162150730129409",
        "createdAt": 1784601721,
        "createTime": "2026-07-21 10:42:01",
        "type": 2,
        "requestId": "request_example_001",
        "ip": "203.0.113.10",
        "requestPath": "/v1/messages",
        "isStream": 1,
        "streamStatus": "正常 (eof)",
        "useTime": 2,
        "firstTokenTime": 1043,
        "modelName": "claude-sonnet-5",
        "tokenName": "default",
        "quotaDollar": "0.006098",
        "billingType": "token_ratio",
        "billingCountMode": "上游返回",
        "requestConversion": "Claude Messages",
        "textInputTokens": 2804,
        "textOutputTokens": 49,
        "cacheTokens": 0,
        "billingProcessText": "输入价格：...，最终费用：$0.006098"
      }
    ]
  }
}
```

<Note>
  `quotaDollar` 为十进制字符串，请用 Decimal / BigDecimal 处理，避免二进制浮点误差。
</Note>

### 信封字段

| 字段           | 类型      | 说明                  |
| ------------ | ------- | ------------------- |
| `code`       | integer | `200` 成功，`401` 鉴权失败 |
| `msg`        | string  | 说明文案                |
| `data.total` | integer | 命中总条数（不是总页数）        |
| `data.rows`  | array   | 当前页记录               |

### 日志条目（常用）

| 字段                      | 类型              | 说明             |
| ----------------------- | --------------- | -------------- |
| `id`                    | string          | 日志 ID，建议按字符串处理 |
| `createdAt`             | integer         | Unix 秒级时间戳     |
| `createTime`            | string          | 格式化创建时间        |
| `type`                  | integer         | 日志类型，见上表       |
| `requestId`             | string \| null  | 请求 ID          |
| `ip`                    | string \| null  | 请求 IP          |
| `requestPath`           | string \| null  | 请求路径           |
| `isStream`              | integer \| null | 是否流式           |
| `streamStatus`          | string \| null  | 流式状态           |
| `useTime`               | integer \| null | 总用时（秒）         |
| `firstTokenTime`        | integer \| null | 首字耗时（毫秒）       |
| `modelName`             | string \| null  | 模型名称           |
| `tokenName`             | string \| null  | Token / Key 名称 |
| `quotaDollar`           | string \| null  | 客户花费（美元）       |
| `billingType`           | string \| null  | 计费类型           |
| `billingCountMode`      | string \| null  | 计费统计方式         |
| `requestConversion`     | string \| null  | 协议转换类型         |
| `textInputTokens`       | integer \| null | 文本输入 Token     |
| `textOutputTokens`      | integer \| null | 文本输出 Token     |
| `cacheCreationTokens5m` | integer \| null | 5 分钟缓存创建 Token |
| `cacheCreationTokens1h` | integer \| null | 1 小时缓存创建 Token |
| `cacheTokens`           | integer \| null | 缓存命中 Token     |
| `billingProcessText`    | string \| null  | 计费过程说明（随语言头变化） |

<Accordion title="多媒体与其它计量字段">
  | 字段                                       | 类型              | 说明         |
  | ---------------------------------------- | --------------- | ---------- |
  | `audioInput` / `audioOutput`             | integer \| null | 音频入/出计量    |
  | `imageInputTokens` / `imageOutputTokens` | integer \| null | 图片 Token   |
  | `videoOutputTokens`                      | integer \| null | 视频输出 Token |
  | `imageCount`                             | integer \| null | 图片数量       |
  | `videoResolution`                        | string \| null  | 视频分辨率      |
  | `toolCallBilling`                        | array \| null   | 工具调用计费明细   |
</Accordion>

## 错误响应

| 场景                  | `code` | 典型 `msg`                                  |
| ------------------- | -----: | ----------------------------------------- |
| 缺少或无效 Authorization |  `401` | `Authorization header missing or invalid` |
| Key 为空              |  `401` | `Authorization key is empty`              |
| Key 无效或已禁用          |  `401` | `无效或已禁用的密钥`                               |
| 时间格式错误              |  `500` | `startTime 格式错误，请使用 yyyy-MM-dd HH:mm:ss`  |
| 时间跨度过大              |  `500` | `时间范围不能超过1个月`                             |

## 接入提示

1. 在服务端保管凭证，勿把完整 Key 打进业务日志。
2. 每次查询控制在 31 天内；需要更长历史请分段请求。
3. 用 `data.total` 算总页数：`ceil(total / pageSize)`，不要把 `total` 当成页数。
4. 先看响应体 `code`，不要仅凭 HTTP 200 判定业务成功。
5. 金额字段按十进制字符串解析，勿用 `float` / `number` 做二次运算。
