日志查询
curl --request GET \
--url https://client.tennda.ai/prod-api/api/logs/openLogimport requests
url = "https://client.tennda.ai/prod-api/api/logs/openLog"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://client.tennda.ai/prod-api/api/logs/openLog', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://client.tennda.ai/prod-api/api/logs/openLog",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://client.tennda.ai/prod-api/api/logs/openLog"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://client.tennda.ai/prod-api/api/logs/openLog")
.asString();require 'uri'
require 'net/http'
url = URI("https://client.tennda.ai/prod-api/api/logs/openLog")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body接口模块
日志查询
按时间与类型分页拉取调用、消费、充值等业务日志
GET
/
prod-api
/
api
/
logs
/
openLog
日志查询
curl --request GET \
--url https://client.tennda.ai/prod-api/api/logs/openLogimport requests
url = "https://client.tennda.ai/prod-api/api/logs/openLog"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://client.tennda.ai/prod-api/api/logs/openLog', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://client.tennda.ai/prod-api/api/logs/openLog",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://client.tennda.ai/prod-api/api/logs/openLog"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://client.tennda.ai/prod-api/api/logs/openLog")
.asString();require 'uri'
require 'net/http'
url = URI("https://client.tennda.ai/prod-api/api/logs/openLog")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body简介
通过开放接口拉取当前凭证可见范围内的业务日志,覆盖消费、充值、错误、退款、管理与测试金等类型,适合对账、排障与用量统计。单次最多 31 天
startTime / endTime 跨度不可超过 31 天;时间格式统一为 yyyy-MM-dd HH:mm:ss。分页默认值
默认
page=1、pageSize=30;pageSize 最大 1000。接口
| 项 | 值 |
|---|---|
| 方法 | GET |
| URL | https://client.tennda.ai/prod-api/api/logs/openLog |
| 鉴权头 | Authorization |
| 语言头 | Accept-Language(zh-CN / en-US,影响 billingProcessText) |
鉴权
请求头支持以下两种写法:Authorization: Bearer sk-your_api_key
Authorization: sk-your_api_key
完整 Key 勿写入 URL、前端、日志或工单。
请求参数
分页
integer
默认值:"1"
页码;
≤ 0 时按 1 处理integer
默认值:"30"
每页条数;
≤ 0 时按 30 处理,上限 1000筛选
string
API Key 名称。仅系统访问令牌鉴权时生效(模糊匹配);API Key 鉴权时不可用
string
模型名称,精确匹配;多个模型用英文逗号分隔
string
请求 ID,精确匹配
string
日志类型,多个值用英文逗号分隔,例如
2,5types 取值 | 含义 |
|---|---|
1 | 充值 |
2 | 消费 |
3 | 管理 |
5 | 错误 |
6 | 退款 |
8 | 测试金 |
时间
string
开始时间,
yyyy-MM-dd HH:mm:ss,含边界string
结束时间,
yyyy-MM-dd HH:mm:ss,含边界Accept-Language 只影响返回字段 billingProcessText 的文案语言:zh-CN / 未传 → 中文,en-US → 英文。请求示例
- curl
- JavaScript
- Python
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'
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);
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"])
成功响应
{
"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"
}
]
}
}
quotaDollar 为十进制字符串,请用 Decimal / BigDecimal 处理,避免二进制浮点误差。信封字段
| 字段 | 类型 | 说明 |
|---|---|---|
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 | 计费过程说明(随语言头变化) |
多媒体与其它计量字段
多媒体与其它计量字段
| 字段 | 类型 | 说明 |
|---|---|---|
audioInput / audioOutput | integer | null | 音频入/出计量 |
imageInputTokens / imageOutputTokens | integer | null | 图片 Token |
videoOutputTokens | integer | null | 视频输出 Token |
imageCount | integer | null | 图片数量 |
videoResolution | string | null | 视频分辨率 |
toolCallBilling | array | null | 工具调用计费明细 |
错误响应
| 场景 | 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个月 |
接入提示
- 在服务端保管凭证,勿把完整 Key 打进业务日志。
- 每次查询控制在 31 天内;需要更长历史请分段请求。
- 用
data.total算总页数:ceil(total / pageSize),不要把total当成页数。 - 先看响应体
code,不要仅凭 HTTP 200 判定业务成功。 - 金额字段按十进制字符串解析,勿用
float/number做二次运算。
⌘I
