curl --get 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>' \
--data-urlencode 'start=2026-09-01T00:00:00+08:00' \
--data-urlencode 'end=2026-09-08T00:00:00+08:00' \
--data-urlencode 'group_by=model'
import requests
response = requests.get(
"https://api.apimart.ai/v1/usage",
headers={"Authorization": "Bearer <token>"},
params={
"start": "2026-09-01T00:00:00+08:00",
"end": "2026-09-08T00:00:00+08:00",
"group_by": "model",
},
timeout=30,
)
payload = response.json()
if not response.ok or not payload.get("success"):
message = payload.get("error", {}).get("message", "Usage query failed")
raise RuntimeError(f"HTTP {response.status_code}: {message}")
print(payload["data"]["total"])
print(payload["data"]["items"])
const url = new URL("https://api.apimart.ai/v1/usage");
url.search = new URLSearchParams({
start: "2026-09-01T00:00:00+08:00",
end: "2026-09-08T00:00:00+08:00",
group_by: "model",
}).toString();
const response = await fetch(url, {
headers: { Authorization: "Bearer <token>" },
});
const payload = await response.json();
if (!response.ok || !payload.success) {
throw new Error(
`HTTP ${response.status}: ${payload.error?.message ?? "Usage query failed"}`,
);
}
console.log(payload.data.total);
console.log(payload.data.items);
{
"success": true,
"data": {
"scope": "key",
"start": 1788192000,
"end": 1788796800,
"tz": "Asia/Shanghai",
"group_by": "model",
"total": {
"amount_usd": 12.3456,
"credits": 123.456,
"requests": 1834,
"prompt_tokens": 902311,
"completion_tokens": 215044
},
"items": [
{
"model": "gpt-5.6-luna",
"amount_usd": 9.1271,
"credits": 91.271,
"requests": 1520,
"prompt_tokens": 880120,
"completion_tokens": 201300
},
{
"model": "sora-2",
"amount_usd": 3.2185,
"credits": 32.185,
"requests": 314,
"prompt_tokens": 22191,
"completion_tokens": 13744
}
]
}
}
{
"success": false,
"error": {
"code": "range_too_large",
"message": "Time range must not exceed 31 days.",
"type": "usage_query_error"
}
}
Account Management
Query Usage and Spending
- Query spending and request statistics for a specified time range
- Filter by model and group by model or calendar day
- Query usage for the current API Key or the entire account
- Returns USD amounts, credits, request counts, and token usage
GET
/
v1
/
usage
curl --get 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>' \
--data-urlencode 'start=2026-09-01T00:00:00+08:00' \
--data-urlencode 'end=2026-09-08T00:00:00+08:00' \
--data-urlencode 'group_by=model'
import requests
response = requests.get(
"https://api.apimart.ai/v1/usage",
headers={"Authorization": "Bearer <token>"},
params={
"start": "2026-09-01T00:00:00+08:00",
"end": "2026-09-08T00:00:00+08:00",
"group_by": "model",
},
timeout=30,
)
payload = response.json()
if not response.ok or not payload.get("success"):
message = payload.get("error", {}).get("message", "Usage query failed")
raise RuntimeError(f"HTTP {response.status_code}: {message}")
print(payload["data"]["total"])
print(payload["data"]["items"])
const url = new URL("https://api.apimart.ai/v1/usage");
url.search = new URLSearchParams({
start: "2026-09-01T00:00:00+08:00",
end: "2026-09-08T00:00:00+08:00",
group_by: "model",
}).toString();
const response = await fetch(url, {
headers: { Authorization: "Bearer <token>" },
});
const payload = await response.json();
if (!response.ok || !payload.success) {
throw new Error(
`HTTP ${response.status}: ${payload.error?.message ?? "Usage query failed"}`,
);
}
console.log(payload.data.total);
console.log(payload.data.items);
{
"success": true,
"data": {
"scope": "key",
"start": 1788192000,
"end": 1788796800,
"tz": "Asia/Shanghai",
"group_by": "model",
"total": {
"amount_usd": 12.3456,
"credits": 123.456,
"requests": 1834,
"prompt_tokens": 902311,
"completion_tokens": 215044
},
"items": [
{
"model": "gpt-5.6-luna",
"amount_usd": 9.1271,
"credits": 91.271,
"requests": 1520,
"prompt_tokens": 880120,
"completion_tokens": 201300
},
{
"model": "sora-2",
"amount_usd": 3.2185,
"credits": 32.185,
"requests": 314,
"prompt_tokens": 22191,
"completion_tokens": 13744
}
]
}
}
{
"success": false,
"error": {
"code": "range_too_large",
"message": "Time range must not exceed 31 days.",
"type": "usage_query_error"
}
}
Use an API Key to query spending within a specified time range, filter by model, and group by model, calendar day, or both. This endpoint returns aggregated results directly; no task creation or task-status polling is required.
Both endpoints provide the same functionality and support CORS. Keep your API Key private; do not expose it in public frontend code.
With this grouping, each
For remaining quota, use Query Token Balance or Query User Balance.
curl --get 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>' \
--data-urlencode 'start=2026-09-01T00:00:00+08:00' \
--data-urlencode 'end=2026-09-08T00:00:00+08:00' \
--data-urlencode 'group_by=model'
import requests
response = requests.get(
"https://api.apimart.ai/v1/usage",
headers={"Authorization": "Bearer <token>"},
params={
"start": "2026-09-01T00:00:00+08:00",
"end": "2026-09-08T00:00:00+08:00",
"group_by": "model",
},
timeout=30,
)
payload = response.json()
if not response.ok or not payload.get("success"):
message = payload.get("error", {}).get("message", "Usage query failed")
raise RuntimeError(f"HTTP {response.status_code}: {message}")
print(payload["data"]["total"])
print(payload["data"]["items"])
const url = new URL("https://api.apimart.ai/v1/usage");
url.search = new URLSearchParams({
start: "2026-09-01T00:00:00+08:00",
end: "2026-09-08T00:00:00+08:00",
group_by: "model",
}).toString();
const response = await fetch(url, {
headers: { Authorization: "Bearer <token>" },
});
const payload = await response.json();
if (!response.ok || !payload.success) {
throw new Error(
`HTTP ${response.status}: ${payload.error?.message ?? "Usage query failed"}`,
);
}
console.log(payload.data.total);
console.log(payload.data.items);
{
"success": true,
"data": {
"scope": "key",
"start": 1788192000,
"end": 1788796800,
"tz": "Asia/Shanghai",
"group_by": "model",
"total": {
"amount_usd": 12.3456,
"credits": 123.456,
"requests": 1834,
"prompt_tokens": 902311,
"completion_tokens": 215044
},
"items": [
{
"model": "gpt-5.6-luna",
"amount_usd": 9.1271,
"credits": 91.271,
"requests": 1520,
"prompt_tokens": 880120,
"completion_tokens": 201300
},
{
"model": "sora-2",
"amount_usd": 3.2185,
"credits": 32.185,
"requests": 314,
"prompt_tokens": 22191,
"completion_tokens": 13744
}
]
}
}
{
"success": false,
"error": {
"code": "range_too_large",
"message": "Time range must not exceed 31 days.",
"type": "usage_query_error"
}
}
Authentication
string
required
Authenticate with the same API Key used for model calls, using a Bearer Token. Get a key from the API Key management page.
Authorization: Bearer YOUR_API_KEY
Queries are available even with a zero balance. This endpoint does not check the balance, but still checks API Key status, expiration, IP allowlists, and account status.
Endpoints
GET /v1/usage
GET /usage
Request parameters
All parameters are passed as URL query parameters.integer | string
Inclusive start time. Accepts a Unix timestamp in seconds or an RFC3339 string with a timezone, such as
2026-09-01T00:00:00+08:00.Defaults to 24 hours before end when omitted. Timestamps use seconds, not milliseconds.integer | string
Exclusive end time. Uses the same formats as
start and defaults to the current time when omitted.Must be later than start, and end - start must not exceed 31 days.string
Model names; all models are included when omitted. Separate multiple models with commas, up to
50 models.Exact, case-insensitive matching. Wildcards are not supported.Example: gpt-5.6-luna,sora-2string
default:"none"
Grouping options:
none: totals only;itemsis an empty arraymodel: group by modeldate: group by calendar daymodel,date: group by both model and calendar day
string
default:"Asia/Shanghai"
IANA timezone name; defaults to
Asia/Shanghai.Only affects calendar-day boundaries when group_by includes date; it does not change the query start or end instants. RFC3339 times are still parsed using their own timezone offsets.string
default:"key"
Query scope:
key: only the current API Key (default)account: all API Keys belonging to the account of the current API Key
The query interval is
[start, end): inclusive start, exclusive end. Using the same boundary as one query’s end and the next query’s start avoids counting that boundary twice.When building URLs manually, encode the + in RFC3339 as %2B. The examples use cURL --data-urlencode, Python params, and JavaScript URLSearchParams to handle encoding automatically.Request examples
Total spending for the current API Key over the last 24 hours
Omit query parameters to use the default time range, scope, and grouping:curl 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>'
Daily spending for a specified model across the account
Query spending from September 11 to September 18, 2026, in Beijing time, excluding September 18:curl --get 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>' \
--data-urlencode 'start=1789056000' \
--data-urlencode 'end=1789660800' \
--data-urlencode 'model=gpt-5.6-luna' \
--data-urlencode 'group_by=date' \
--data-urlencode 'scope=account' \
--data-urlencode 'tz=Asia/Shanghai'
Group by model and calendar day
curl --get 'https://api.apimart.ai/v1/usage' \
--header 'Authorization: Bearer <token>' \
--data-urlencode 'start=2026-09-01T00:00:00+08:00' \
--data-urlencode 'end=2026-09-08T00:00:00+08:00' \
--data-urlencode 'model=gpt-5.6-luna,sora-2' \
--data-urlencode 'group_by=model,date' \
--data-urlencode 'tz=Asia/Shanghai'
items entry contains both model and date.
Response fields
boolean
Whether the query succeeded:
true on success, false for usage-query errors.object
On success, contains the query range, totals, and grouped details.
Show data properties
Show data properties
string
Query scope:
key or account.integer
Actual query start time as a Unix timestamp in seconds, inclusive.
integer
Actual query end time as a Unix timestamp in seconds, exclusive.
string
Timezone used for calendar-day grouping.
string
Grouping:
none, model, date, or model,date.object
Totals within the query range; see the statistics below.
object[]
Grouped details, sorted by
amount_usd in descending order. Empty when group_by=none. Each entry includes the statistics below.- Entries include
modelwhengroup_byincludesmodel - Entries include
datewhengroup_byincludesdate, formatted asYYYY-MM-DDwith calendar days determined bytz
data.total and data.items[] share these statistics:
| Field | Type | Description |
|---|---|---|
amount_usd | number | USD amount, rounded to 6 decimal places |
credits | number | Platform credits, equal to amount_usd × 10, matching the units displayed on the website |
requests | integer | Number of successfully billed calls |
prompt_tokens | integer | Input tokens; usually 0 for image/video models billed per request or per second |
completion_tokens | integer | Output tokens; usually 0 for image/video models billed per request or per second |
object
Returned for usage-query errors, with
code, message, and type; type is usage_query_error. Authentication errors with HTTP 401 / 403 are returned by the authentication layer.Rate limits and caching
- Up to
60queries per API Key per minute; global API rate limits also apply - Results with identical parameters are cached for
60seconds; theX-Usage-Cacheresponse header ishitormiss - Usage records are typically available within 1 second, but the last minute of data may be incomplete, with additional cache delay
- Poll no more frequently than once a minute; do not use this endpoint as a real-time billing notification
Accounting rules
- Uses successfully billed call records, the same data as the website dashboard
- Failed calls and tasks refunded after failure are excluded; no manual offset is needed. Partially successful image batches are billed for the images actually delivered
- Spending is attributed to the billing posting time. Asynchronous image/video tasks are posted at completion, not submission; tasks crossing midnight belong to the completion day
- Deleting and recreating an API Key creates a new Key; querying
scope=keywith the new Key does not include the old Key’s history - Manual balance adjustments are not call spending and are excluded
- Data after April 27, 2026, is available
Error handling
| HTTP status | error.code | Description |
|---|---|---|
| 400 | invalid_start / invalid_end | Invalid start or end time format |
| 400 | invalid_range | end is not later than start |
| 400 | range_too_large | Range exceeds 31 days; split it into multiple queries |
| 400 | invalid_tz | Unknown IANA timezone |
| 400 | invalid_group_by | Invalid grouping option |
| 400 | invalid_scope | Invalid query scope |
| 400 | too_many_models | More than 50 models |
| 401 / 403 | — | Invalid or expired API Key, IP not allowed, or disabled account |
| 429 | — | Exceeds 60 queries per Key per minute, or a global API rate limit |
| 503 | usage_unavailable | Usage data is temporarily unavailable; retry later |
A
503 usage_unavailable response returns no amounts. It means the query is unavailable, not that spending is zero. Do not convert failed responses into zero amounts or overwrite a previous successful result.Comparison with other endpoints
| Endpoint | Capability |
|---|---|
GET /v1/dashboard/billing/usage | Cumulative spending only; no model or time filters |
POST /v1/logs/export | Asynchronous export of call details (CSV / XLSX); aggregate them yourself |
GET /v1/usage | Query by time and model; directly returns totals and grouped spending |