List product bills
Product-dimension bills (fees aggregated by model/business type) with cursor pagination (has_more/next). Amounts are in milli-cent; data for day T becomes available at 07:00 (UTC+8) on day T+1.
curl --request GET \
--url https://api.moonshot.ai/v1/admin/organizations/billings/product_bills \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.moonshot.ai/v1/admin/organizations/billings/product_bills"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.moonshot.ai/v1/admin/organizations/billings/product_bills', 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://api.moonshot.ai/v1/admin/organizations/billings/product_bills",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://api.moonshot.ai/v1/admin/organizations/billings/product_bills"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.moonshot.ai/v1/admin/organizations/billings/product_bills")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moonshot.ai/v1/admin/organizations/billings/product_bills")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"product": "<string>",
"product_type": "<string>",
"business_type": "<string>",
"total_fee": 1,
"recharge_fee": 1,
"voucher_fee": 1
}
],
"has_more": true,
"next": "<string>"
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}billing:read scope.400 data_not_ready. Amounts are split into cash (recharge_fee) and voucher (voucher_fee) parts summing to total_fee (actual amount charged). The time window is left-closed, right-open, aligned to CST day boundaries.Fields and reconciliation
product: product identifier (model/product name, e.g.kimi-k2.5,moonshot-v1-8k);product_type: product type;business_type: business type (e.g.chat,batch). The enums grow with the product line — clients should keep raw strings and ignore unknown values.- Reconciling with
daily_billsmodel_details: product bills aggregate by product (not by key);total_feein daily bills minus the sum ofmodel_detailsrows equals non-token charges (cache-call, tool_call, cache storage, BatchAPI, etc.), which are only included in the outer totals.
Authorizations
Send the Admin API secret as a Bearer token in the Authorization header (Bearer sk-admin-***). Create Admin Keys under Console → Organization → Admin API Keys.
Query Parameters
Start time in milliseconds, inclusive, e.g. 1790784000000 (2026-10-01 00:00 CST).
x >= 0End time in milliseconds, exclusive, e.g. 1792598400000 (2026-10-22 00:00 CST).
x >= 0Project IDs. Every project must belong to the authenticated organization.
Business API key IDs. Every key must belong to the authenticated organization.
Page size. Defaults to 100, maximum 1000. Rows are bounded by the organization's distinct product/business-type combinations, so the default fetches everything in one page for typical organizations.
1 <= x <= 1000Cursor from the previous response next field. The cursor carries only the page position; all query parameters must be restated on every page. Keep them unchanged while paginating (except limit) — the server does not check them for consistency.
Was this page helpful?
curl --request GET \
--url https://api.moonshot.ai/v1/admin/organizations/billings/product_bills \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.moonshot.ai/v1/admin/organizations/billings/product_bills"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.moonshot.ai/v1/admin/organizations/billings/product_bills', 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://api.moonshot.ai/v1/admin/organizations/billings/product_bills",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://api.moonshot.ai/v1/admin/organizations/billings/product_bills"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.moonshot.ai/v1/admin/organizations/billings/product_bills")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moonshot.ai/v1/admin/organizations/billings/product_bills")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"product": "<string>",
"product_type": "<string>",
"business_type": "<string>",
"total_fee": 1,
"recharge_fee": 1,
"voucher_fee": 1
}
],
"has_more": true,
"next": "<string>"
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}