Skip to main content

Overview

TextQL exposes usage data through several channels. Each answers a different question — pick the right one before building.
What you wantWhere to get it
ACU spend or dollar cost, by user or time periodUsage API (GET /v1/billing/usage) — this page
All conversations across all users and sourcesChat List API (POST /v1/chat/list)
Tokens and cost per conversationGetLlmUsage RPC
Message content of a conversationChat API (GET /v2/chats/{id})
Raw token counts by model (reconcile against provider bill)Token Usage API — BYOK only

Data Sources Reference

Usage API — GET /v1/billing/usage

ACU consumption aggregated by user × time bucket. Use for billing dashboards and spend tracking across teams. Contains: organization, email, category (llm_tokens, compute_hours, cell_executions), acu, start_datetime, end_datetime Does not contain: per-conversation breakdown, raw token counts, cost in dollars

Chat List API — POST /v1/chat/list

Returns all conversations in the org across every source. Requires an admin API key — a member-scoped key silently returns only that member’s chats.
curl -s -X POST 'https://app.textql.com/v1/chat/list' \
  -H "tql_api_key: $K" \
  -H 'Content-Type: application/json' \
  -d '{"memberOnly": false}'
Contains: chat_id, title, source (Slack, UI, playbook), creator (email), created_at, updated_at Does not contain: token counts, cost, message content Key parameters:
ParameterTypeDescription
memberOnlybooleanfalse returns all org chats; true (default) returns only the key holder’s chats
sourcesarrayFilter by source: "slack", "ui", "playbook"
limitintPage size (default 50)
offsetintPagination offset

GetLlmUsage — per-conversation tokens and cost

Returns token breakdown and estimated cost for a specific chat. Requires an admin API key for include_costs.
curl -s -X POST 'https://app.textql.com/rpc/public/textql.rpc.public.chat.ChatService/GetLlmUsage' \
  -H "tql_api_key: $K" \
  -H 'Content-Type: application/json' \
  -d '{"chat_id": "YOUR_CHAT_ID", "include_costs": true}'
Contains: one record per LLM call within the chat — input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens, model_name, timestamp, and estimated_cost (admin only). Sum across the array for conversation totals. Does not contain: ACU values, message content Typical pattern: call POST /v1/chat/list to get all chat_ids, then call GetLlmUsage for each.

Chat API — GET /v2/chats/{id}

Returns the full content of a single conversation including messages.
curl 'https://app.textql.com/v2/chats/YOUR_CHAT_ID' \
  -H "tql_api_key: $K"
Contains: message content, source, participants, timestamps Does not contain: token counts, cost
The TextQL Usage connector (visible inside Ana) contains the same thread-level fields as the Chat List API but is designed for interactive querying inside Ana — not for backend polling or external integrations. It does not contain ACU values or dollar cost.
TextQL Usage connector in chat
Base URL: https://app.textql.com/v1/billing

Authentication

All requests require a Bearer token. Your token is a Base64-encoded string in the format {member_id}:{api_token}, created in Settings → Developers → API Keys. Pass it in one of two ways:
# Authorization header
-H 'Authorization: Bearer YOUR_TOKEN'

# Or as a custom header
-H 'tql_api_key: YOUR_TOKEN'

Your First Request

Fetch the last 90 days of usage for your organization with a single call:
curl 'https://app.textql.com/v1/billing/usage' \
  -H 'Authorization: Bearer YOUR_TOKEN'
Response:
{
  "data": [
    {
      "start_datetime": "2026-01-31T00:00:00Z",
      "end_datetime": "2026-02-01T00:00:00Z",
      "organization": "acme-engineering",
      "email": "m.chen@acme.com",
      "category": "llm_tokens",
      "acu": 8241.05
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 100,
    "total_count": 3
  }
}
Each record represents one user’s usage within one time bucket, for one category.

Parameters

All parameters are optional query parameters on GET /usage.

Date Range

ParameterFormatDefaultDescription
start_dateRFC 333990 days before end_dateInclusive lower bound
end_dateRFC 3339Current UTC timeExclusive upper bound
# Usage for January 2026
curl 'https://app.textql.com/v1/billing/usage?start_date=2026-01-01T00:00:00Z&end_date=2026-02-01T00:00:00Z' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Granularity

Controls the size of each time bucket. Defaults to day.
ValueBucket size
hour1 hour
day1 calendar day
month1 calendar month
# Monthly rollup
curl 'https://app.textql.com/v1/billing/usage?granularity=month' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Filtering

By organization — useful for tenants with multiple orgs:
curl 'https://app.textql.com/v1/billing/usage?organization=acme-engineering,acme-research' \
  -H 'Authorization: Bearer YOUR_TOKEN'
By user email — case-insensitive:
curl 'https://app.textql.com/v1/billing/usage?email=j.ramirez@acme.com,s.patel@acme.com' \
  -H 'Authorization: Bearer YOUR_TOKEN'
By usage category:
CategoryWhat it measures
llm_tokensLLM inference consumption
compute_hoursPython and execution environment usage
cell_executionsIndividual cell runs
curl 'https://app.textql.com/v1/billing/usage?category=llm_tokens,compute_hours' \
  -H 'Authorization: Bearer YOUR_TOKEN'
Filters can be combined freely:
# LLM usage for one user, by hour, for a specific week
curl 'https://app.textql.com/v1/billing/usage?email=m.chen@acme.com&category=llm_tokens&granularity=hour&start_date=2026-01-27T00:00:00Z&end_date=2026-02-03T00:00:00Z' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Sorting

Use the sort parameter to control result order. Prefix with - for descending.
ValueDescription
start_datetimeOldest first
-start_datetimeNewest first (default)
acuLowest usage first
-acuHighest usage first
emailAlphabetical by user
-emailReverse alphabetical by user
curl 'https://app.textql.com/v1/billing/usage?sort=-acu' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Pagination

ParameterDefaultMax
page_size1001000
page1
# Page 2, 50 records per page
curl 'https://app.textql.com/v1/billing/usage?page=2&page_size=50' \
  -H 'Authorization: Bearer YOUR_TOKEN'
Use pagination.total_count in the response to calculate how many pages exist.

Code Examples

Python — fetch all records across pages:
import requests

TOKEN = "your-token"
BASE = "https://app.textql.com/v1/billing"
headers = {"Authorization": f"Bearer {TOKEN}"}

def get_all_usage(**params):
    records = []
    page = 1
    while True:
        resp = requests.get(f"{BASE}/usage", headers=headers, params={**params, "page": page, "page_size": 1000})
        data = resp.json()
        records.extend(data["data"])
        if len(records) >= data["pagination"]["total_count"]:
            break
        page += 1
    return records

# Example: all LLM usage for January, grouped by month
usage = get_all_usage(
    start_date="2026-01-01T00:00:00Z",
    end_date="2026-02-01T00:00:00Z",
    granularity="month",
    category="llm_tokens",
)
JavaScript:
const TOKEN = "your-token";
const BASE = "https://app.textql.com/v1/billing";

async function getUsage(params = {}) {
  const query = new URLSearchParams(params).toString();
  const res = await fetch(`${BASE}/usage?${query}`, {
    headers: { Authorization: `Bearer ${TOKEN}` },
  });
  return res.json();
}

// Example: top spenders this month
const data = await getUsage({
  granularity: "month",
  sort: "-acu",
  page_size: 10,
});

Response Fields

FieldTypeDescription
start_datetimestring (UTC)Start of the time bucket, inclusive
end_datetimestring (UTC)End of the time bucket, exclusive
organizationstringOrganization name
emailstringUser email (lowercase). Empty if usage cannot be attributed to a specific user
categorystringUsage category
acunumberUsage in ACUs. Records with zero or negative values are omitted

Error Reference

StatusCodeCause
400invalid_parameterBad date range, unknown category, unknown org, or invalid granularity
401unauthorizedToken is missing, invalid, or expired
403forbiddenToken does not have access to the requested organization’s data

Troubleshooting & Support

ProblemWhat to check
401 on every requestConfirm your token is Base64-encoded in {member_id}:{api_token} format and hasn’t expired
403 on a specific orgYour API key may not have access to that organization — check your role in Settings → Members
Empty data arrayThe filters you applied may return no records — try widening the date range or removing category/email filters
acu values seem lowRecords with zero or negative ACU are omitted; usage may also be split across multiple category buckets
Unknown org errorThe organization value must match the org name exactly as it appears in TextQL
If you’re still running into issues, contact support at support@textql.com and include the full request URL and response body.