# Reconcile charges Use task billing to check the reservation, debits, refunds and amount due of every task. Each task has a bill: a summary and a series of permanent billing events. The summary answers how much the task charged in total; the events show how the money moved. ## Read the bill ```bash curl --request GET "${CHENVOYA_BASE_URL}/v1/video/tasks/${TASK_ID}/billing" \ --header "Authorization: Bearer ${CHENVOYA_API_KEY}" ``` ```python 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) ``` ```javascript // Needs Node.js 20 or later; save it as a .mjs file and run it. 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; ``` ```go 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) } ``` The summary covers the whole task and never turns into a subtotal of the event page. Page through events with `cursor` and `page_size`; the last page has a null `next_cursor`. ## Summary fields | Field | Meaning | | --- | --- | | `reserved_amount` | Amount reserved for the task. | | `charged_amount` | Charge recorded for the task. | | `funding_debit_amount` | Amount actually debited from your balance. | | `funding_refund_amount` | Amount actually returned to your balance. | | `outstanding_receivable` | Amount due that has not been collected. | | `final_actual_cost` | Final charge; `null` until settlement is final. | ## Billing events Every movement of money is an event, such as `hold_created` for a new reservation, `charge_captured` for a charge and `hold_released` for a released reservation. Creating, increasing, reducing or releasing a reservation by itself is not a debit, refund or change in the amount due; read the amount fields. Every event type is on [Statuses and reasons](./api-docs-en-api-statuses.md#billing-event). ## When billing needs review The usage of a few tasks needs review. Their `settlement_status` is `reconciliation_required`, `final_actual_cost` is `null`, and `reconciliation` gives the reason `reason_code`, the missing meters `missing_meters` and whether you need to act in `customer_action_required`. After the review the settlement becomes `settled` or `settled_with_receivable`. ## Correlation IDs `request_id` and `billing_correlation_id` stay the same across the task, its bill and its events, so you can match your orders with our bills. ## Next steps - [How billing works](./api-docs-en-billing.md): Funds for the upper bound are reserved at creation and settled on actual usage; failed and cancelled tasks are free. - [Read task billing](./api-docs-en-api-video-tasks-billing.md): Retrieve the whole-task billing summary and one ordered page of permanent billing events. - [Statuses and reasons](./api-docs-en-api-statuses.md): Every value of the task, delivery, settlement, asset and billing fields.