Z Zise Developers English

取导出件(响应体是 xlsx,不是 JSON)

GET /v1/reports/{id}/content scope: merchant:read
商户自身

⚠ 本层唯一一个非 JSON 出参的端点。 响应是Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,带Content-Disposition: attachment,并且Cache-Control: private, no-store(带鉴权、且过期后必须真的取不到,所以不进任何中间缓存)。无条件 JSON.parse 响应体的 SDK 会在这里炸。

每次取件都过一遍这把 Key 的鉴权 —— 这不是一条可以转发出去的链接。

文件是 typed xlsx:金额列是 Excel Number(带小数位,可直接 SUM),UID / 单号是文本(不会被吃掉前导零或变成科学计数)。打开 CSV 再手改列类型做不到这一点,所以不再提供 CSV。

路径参数

字段类型必填说明
id string 必填 任务 id,rep_<uuid> 或裸 <uuid> 都认

响应

200xlsx 文件本体
400state_invalid —— 三种情况同一个响应:还没生成好 · 生成失败 · 已过期(生成件已下架)。⚠ 具体在哪一档去 GET /v1/reports/{id} 看(那里有 status、error、expires_at); 这里不下发内部状态名。 ⚠ 同一个 id 重试不会变 —— 该做的是重新发起一次导出。
403insufficient_scope 缺 merchant:read
404resource_not_found(含「属于别的商户」,同一响应)

深入说明

逐 kind 的列(顺序即文件里的顺序)

daily:


day,line,asset,orders,
member_paid,member_paid_minor,
merchant_paid,merchant_paid_minor,
merchant_margin,merchant_margin_minor,
ledger_scale,display_scale

pnl 与 line:<line>(多了窗口两列,其余同上):


period_from,period_to,line,asset,orders,
member_paid,member_paid_minor,
merchant_paid,merchant_paid_minor,
merchant_margin,merchant_margin_minor,
ledger_scale,display_scale

statements:


posted_at,business,ref_table,ref_id,asset,
merchant_paid,merchant_paid_minor,
ledger_scale,display_scale

⚠ 窗口两列必须进文件,因为 pnl 的每一行都是整个窗口的合计 ——文件本身不带口径的话,两份不同区间的导出件长得一模一样,而它们会同时躺在你财务的下载目录里。

三条口径,照着写解析器

  • 金额同时给两种形态:*_paid / *_margin 是 Excel 数字(打开就能 SUM),*_minor 是同一个数的定点整数。随行带 ledger_scale。
  • ⚠ 位数取不到时金额格是空的(资产已下架或未登记),不兜底成 6 位。空格子至少能被人看见,一个错 100 倍的数不能。这时 ledger_scale / display_scale 两列同样是空。
  • 窗口口径按 kind 分:daily 的窗口不含今天(日汇总由我方次日算,放一行 0 进去会被读成「今天没有业务」),是**截至昨天的days 天;pnl / line: / statements 是近 days 天到此刻**,含今天的部分数据。

另外两件事:

  • line 列可能出现 other —— 那是「有业务表还没登记进映射」的兜底行。它不是错误,但也不该长期存在;看到它请告诉我方。
  • 我方的收入与我方付给服务方的成本一个字都不进文件。你看到的只有「你付了多少」。换个格式不会让这条红线消失。

merchant_margin = member_paid − merchant_paid(你的会员实付减去从你预付里扣掉的),它不是账本上的某一列。

请求
curl -X GET 'https://api.zinfra.vip/v1/reports/{id}/content' \
  -H 'x-auth-token: Bearer $TOKEN'
const res = await fetch("https://api.zinfra.vip/v1/reports/{id}/content", {
  method: "GET",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
  },
});
// 金额按字符串读,别让它变成 number
const data = await res.json();
import requests

res = requests.get(
    "https://api.zinfra.vip/v1/reports/{id}/content",
    headers={
        "x-auth-token": "Bearer $TOKEN",
    },
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()
req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/reports/{id}/content",
    nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
res, err := http.DefaultClient.Do(req)
// 金额字段用 string 接,不要 float64
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zinfra.vip/v1/reports/{id}/content"))
    .header("x-auth-token", "Bearer $TOKEN")
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
// 金额字段用 String / BigDecimal,不要 double
$ch = curl_init('https://api.zinfra.vip/v1/reports/{id}/content');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
  ],
]);
$res = curl_exec($ch);
// 金额用 bcmath / 字符串,不要 floatval
200
// spec 里还没有这个 operation 的响应示例