Overview
The Token Usage API returns raw LLM token counts aggregated by time bucket, organization, member, and model. Use it to reconcile usage against your own model provider (AWS Bedrock, Anthropic, etc.), build cost dashboards, or audit inference by user and model. This API reports tokens, not ACUs. For ACU-based billing data, use the Usage API (GET /v1/billing/usage).
Availability: BYOK deployments only. Deployments that use the TextQL-managed model provider cannot access this API.
Base URL: https://app.textql.com/v1/billing
Endpoint: GET /v1/billing/token-usage
Authentication
Same as the Usage API. All requests require an API key withbilling:read permission.
Create keys in Settings → Developers → API Keys. The token is Base64-encoded {member_id}:{api_token}.
Pass it in one of two ways:
organization).
Your First Request
Fetch the last 90 days of token usage for your tenant:Query Parameters
All parameters are optional query parameters onGET /token-usage.
Date range
| Parameter | Format | Default | Description |
|---|---|---|---|
start_date | RFC 3339 (UTC) | 90 days before end_date | Inclusive lower bound |
end_date | RFC 3339 (UTC) | Current UTC time | Exclusive upper bound |
start_datemust be beforeend_date.- The window
end_date − start_datecannot exceed 90 days.
Granularity
Controls time bucket size. Default:day.
| Value | Bucket size | end_datetime offset |
|---|---|---|
hour | 1 hour | start_datetime + 1 hour |
day | 1 calendar day (UTC) | start_datetime + 1 day |
month | 1 calendar month (UTC) | start_datetime + 1 month |
Filtering
By organization — comma-separated organization names (not UUIDs). Omit to include all organizations in the tenant.400 invalid_parameter.
By user email — comma-separated, case-insensitive. Only members whose email matches (in the selected orgs) are included. If no members match, the response is an empty data array with 200 OK.
claude-sonnet-4-6, gpt-4o). Exact match.
Sorting
Usesort to order results before pagination. Prefix with - for descending. Default: -start_datetime (newest buckets first).
| Value | Description |
|---|---|
start_datetime | Oldest bucket first |
-start_datetime | Newest bucket first (default) |
email | Alphabetical by user email |
-email | Reverse alphabetical by email |
model | Alphabetical by model name |
-model | Reverse alphabetical by model |
total_tokens | Lowest total tokens first |
-total_tokens | Highest total tokens first |
Pagination
| Parameter | Default | Max |
|---|---|---|
page_size | 100 | 1000 |
page | 1 | — |
pagination.total_count to compute total pages. Requesting a page beyond the last page returns an empty data array with the requested page and correct total_count.
Response Fields
Top level
| Field | Type | Description |
|---|---|---|
data | array | Token usage records (see below) |
pagination.page | integer | Current page (1-based) |
pagination.page_size | integer | Page size used for this response |
pagination.total_count | integer | Total matching records across all pages |
Record object (data[])
| Field | Type | Description |
|---|---|---|
start_datetime | string (UTC, RFC 3339) | Start of the time bucket, inclusive |
end_datetime | string (UTC, RFC 3339) | End of the time bucket, exclusive |
organization | string | Organization name |
email | string | Member email, lowercase. Empty string if usage is non-attributed (see below) |
model | string | Model name |
input_tokens | integer | Sum of input/prompt tokens |
cache_read_input_tokens | integer | Sum of cache-read input tokens |
cache_write_input_tokens | integer | Sum of cache-write input tokens |
output_tokens | integer | Sum of output/completion tokens |
total_tokens | integer | Sum of all four token fields above |
request_count | integer | Number of LLM usage events in this bucket |
total_tokens calculation:
Member Attribution
Usage is attributed to a member whenmember_id is present on the underlying usage event and the member’s email is not a TextQL staff domain.
Non-attributed usage (empty email):
- Usage with no member attribution
- Usage from
@textql.comor*.textql.comemail addresses (TextQL staff)
"email": "". Clients may display these as “(non-attributed)” in UI.
BYOK Requirement
This API is only available when your deployment uses your own model provider (BYOK — bring your own keys).| Deployment type | Token Usage API |
|---|---|
| BYOK (customer-managed provider) | Available |
| TextQL-managed provider | Not available — 403 forbidden |
Comparison with Usage API
| Usage API | Token Usage API | |
|---|---|---|
| Path | GET /v1/billing/usage | GET /v1/billing/token-usage |
| Metric | ACU | Raw token counts |
| Grouping | category (llm_tokens, compute_hours, …) | model name |
| BYOK required | No | Yes |
| Extra fields | category, acu, cost_center | model, input_tokens, cache_*, output_tokens, total_tokens, request_count |
| Sort options | includes acu / -acu | includes total_tokens, model |
organization / email filters, date range defaults, 90-day max window, granularity, pagination.
Code Examples
Python — paginate all token usage for January
JavaScript — top models by token volume (last 90 days)
Error Reference
Errors use the same envelope as the Usage API:| HTTP status | code | Typical cause |
|---|---|---|
| 400 | invalid_parameter | Invalid date format; start_date ≥ end_date; date range > 90 days; invalid granularity or sort; invalid email format; unknown organization name; invalid page / page_size |
| 403 | forbidden | Missing/invalid/expired API key; insufficient permissions; or deployment is not BYOK |
| 500 | internal_error | Server-side failure retrieving usage |
code: "forbidden".
Troubleshooting & Support
| Problem | What to check |
|---|---|
403 token usage API is only available for BYOK deployments | Deployment must use customer-managed model keys, not TextQL-managed provider |
| 403 on every request | Token format ({member_id}:{api_token} Base64), expiry, and billing:read permission |
Empty data | Widen date range; remove email / model filters; confirm LLM usage exists for the tenant |
| Unknown organization | organization must be the exact org name as shown in TextQL, not a UUID |
email is empty on some rows | Expected for non-attributed usage (unattributed events or TextQL staff) |
| Counts differ from provider bills | This API reflects TextQL-recorded usage; provider billing may use different bucketing or attribution |