对账
用任务账单接口核对每个任务的预留、扣款、退款和应收。
本页内容
每个任务都有一份账单:一个汇总加一串不可变的账单事件。汇总回答「这个任务一共收了多少」,事件回答「钱是怎么动的」。
读取账单
curl --request GET "${CHENVOYA_BASE_URL}/v1/video/tasks/${TASK_ID}/billing" \
--header "Authorization: Bearer ${CHENVOYA_API_KEY}"import urllib.request
import urllib.parse
import json
import os
import sys
import re
import uuid
key = os.environ["CHENVOYA_API_KEY"].strip()
if not key or re.search(r"[\x00-\x1f\x7f-\x9f]", key):
sys.exit("Set CHENVOYA_API_KEY to a non-empty value without control characters")
base = os.environ["CHENVOYA_BASE_URL"].rstrip("/")
headers = {"Authorization": "Bearer " + key}
TASK_ID = os.environ["TASK_ID"]
path = "/v1/video/tasks/{task_id}/billing".replace("{task_id}", urllib.parse.quote(TASK_ID, safe=""))
request = urllib.request.Request(base + path, data=None, headers=headers, method="GET")
try:
with urllib.request.urlopen(request) as response:
print(response.read().decode("utf-8"))
except urllib.request.HTTPError as error:
print(error.read().decode("utf-8"))
sys.exit(1)// 需要 Node.js 20 及以上版本,保存为 .mjs 文件后运行。
const key = process.env.CHENVOYA_API_KEY?.trim();
if (!key || /[\x00-\x1f\x7f-\x9f]/.test(key)) {
console.error("Set CHENVOYA_API_KEY to a non-empty value without control characters");
process.exit(1);
}
const base = process.env.CHENVOYA_BASE_URL;
if (!base) throw new Error("Set CHENVOYA_BASE_URL");
const headers = {Authorization: `Bearer ${key}`};
const TASK_ID = process.env.TASK_ID;
if (!TASK_ID) throw new Error("Set TASK_ID");
const path = "/v1/video/tasks/{task_id}/billing".replace("{task_id}", encodeURIComponent(TASK_ID));
const response = await fetch(base.replace(/\/$/, "") + path, {method: "GET", headers, body: undefined});
console.log(await response.text());
if (!response.ok) process.exitCode = 1;package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"regexp"
"strings"
)
func main() {
key := strings.TrimSpace(os.Getenv("CHENVOYA_API_KEY"))
if key == "" || regexp.MustCompile(`[\x00-\x1f\x7f-\x9f]`).MatchString(key) {
fail("Set CHENVOYA_API_KEY to a non-empty value without control characters")
}
base := strings.TrimRight(os.Getenv("CHENVOYA_BASE_URL"), "/")
if base == "" {
fail("Set CHENVOYA_BASE_URL")
}
taskID := os.Getenv("TASK_ID")
if taskID == "" {
fail("Set TASK_ID")
}
path := strings.Replace("/v1/video/tasks/{task_id}/billing", "{task_id}", url.PathEscape(taskID), 1)
request, err := http.NewRequest("GET", base+path, nil)
if err != nil {
fail(err.Error())
}
request.Header.Set("Authorization", "Bearer "+key)
response, err := http.DefaultClient.Do(request)
if err != nil {
fail(err.Error())
}
text, err := io.ReadAll(response.Body)
response.Body.Close()
if err != nil {
fail(err.Error())
}
fmt.Println(string(text))
if response.StatusCode < 200 || response.StatusCode > 299 {
os.Exit(1)
}
}
func fail(message string) {
fmt.Fprintln(os.Stderr, message)
os.Exit(1)
}汇总属于整个任务,不会因为事件分页变成当前页的小计。事件按 cursor 和 page_size 翻页,最后一页的 next_cursor 为 null。
汇总字段
| 字段 | 含义 |
|---|---|
reserved_amount | 任务预留的金额。 |
charged_amount | 任务的计费金额。 |
funding_debit_amount | 实际从余额扣减的金额。 |
funding_refund_amount | 实际退回余额的金额。 |
outstanding_receivable | 尚未收取的应收金额。 |
final_actual_cost | 最终实际费用;结算确定前为 null。 |
账单事件
每次资金变动都记一条事件,例如创建预留的 hold_created、收取费用的 charge_captured、释放预留的 hold_released。预留的创建、增加、减少和释放本身不表示扣款、退款或应收变动,金额以各金额字段为准。全部事件类型见「状态与原因」。
需要核对时
少数任务的用量需要核对,这时 settlement_status 为 reconciliation_required,final_actual_cost 为 null,reconciliation 给出核对原因 reason_code、缺少的计量字段 missing_meters,以及是否需要你操作的 customer_action_required。核对完成后结算状态变为 settled 或 settled_with_receivable。
关联标识
request_id 和 billing_correlation_id 在任务、账单和回调里保持一致,可以用来把你的订单和我们的账单对上。