Usage Export (FOCUS)
Export Cencori usage and spend as FOCUS 1.2 records for FinOps tools, data warehouses, and chargeback.
GET /v1/usage/focus returns your Cencori usage as FOCUS 1.2 records, the FinOps Foundation's open format for billing data. Any tool that reads FOCUS, such as CostGraph, a warehouse job or your own chargeback script, can put AI spend through Cencori next to the rest of your cloud bill without a Cencori-specific connector.
Each record covers one UTC day × project × environment × model provider × model × endpoint family × sub-account.
Authentication
Use one of:
Create usage export keys in Organization settings → Advanced → Usage export. Owners and admins can create and revoke them. The key is shown once. Give FinOps tools an export key rather than a project key: an export key cannot spend money if it leaks.
curl https://api.cencori.com/v1/usage/focus \
-H "Authorization: Bearer $CENCORI_USAGE_EXPORT_KEY"Query parameters
The default window is yesterday because a day is settled once it has closed. Request logs are written as requests finish, so the current day keeps growing.
Response
{
"object": "list",
"focus_version": "1.2",
"charge_period_start": "2026-10-13T00:00:00.000Z",
"charge_period_end": "2026-10-14T00:00:00.000Z",
"sub_account": "end_user",
"data": [
{
"BillingAccountId": "8f1c…",
"BillingAccountName": "Acme",
"BillingCurrency": "USD",
"BillingPeriodStart": "2026-10-01T00:00:00.000Z",
"BillingPeriodEnd": "2026-11-01T00:00:00.000Z",
"ChargePeriodStart": "2026-10-13T00:00:00.000Z",
"ChargePeriodEnd": "2026-10-14T00:00:00.000Z",
"ChargeCategory": "Usage",
"ChargeDescription": "anthropic/claude-sonnet-5 chat (1204 requests)",
"Provider": "Cencori",
"Publisher": "anthropic",
"ServiceName": "Cencori Text Generation",
"ServiceCategory": "AI and Machine Learning",
"ServiceSubcategory": "Generative AI",
"SubAccountId": "cust_4711",
"SubAccountType": "End User",
"ResourceId": "b7e2…",
"ResourceName": "Support bot",
"ResourceType": "Project",
"SkuId": "anthropic/claude-sonnet-5",
"SkuMeter": "chat/tokens",
"ConsumedQuantity": "18420931",
"ConsumedUnit": "Tokens",
"BilledCost": "41.2203150000",
"EffectiveCost": "41.2203150000",
"ListCost": "41.2203150000",
"ContractedCost": "41.2203150000",
"Tags": { "cencori:project": "b7e2…", "cencori:environment": "production", "cencori:endpoint": "chat" },
"x_RequestCount": "1204",
"x_InputTokens": "2210441",
"x_CacheReadTokens": "14988120",
"x_CacheWriteTokens": "412004",
"x_OutputTokens": "810366",
"x_UnsplitRequests": "0",
"x_UpstreamProviderCost": "41.220315"
}
],
"has_more": false,
"next_cursor": null
}Costs and quantities are decimal strings, so no precision is lost in JSON.
What the costs mean
BilledCost,EffectiveCost,ListCostandContractedCostare what Cencori charged for the usage. Cencori adds no markup to provider rates, so the four are equal.- BYOK usage reports a cost of zero. Your own provider account bills it, not Cencori. If your FinOps tool also reads that provider's bill directly, reporting it here would count it twice. What the provider charged is still visible in
x_UpstreamProviderCost. - Requests that cost nothing and used no tokens are left out. These are refusals, rate limits and errors before a provider was called. They are still in your request logs.
Services
ServiceName says what kind of work the cost was for:
Token buckets
Providers price prompt tokens differently depending on whether they were read from a prompt cache, written to one, or neither. Each record carries all of them:
ConsumedQuantity is the total of all tokens. For endpoints that don't bill by token, such as image generation, it is the request count and ConsumedUnit is Requests.
x_UnsplitRequests counts requests whose input and cache split is unknown: requests logged before buckets were recorded (October 2026), or ones where a provider reported cache activity without the uncached count. When it is not zero, the bucket columns undercount, but the cost columns are still exact.
Paging
Follow next_cursor until has_more is false. Pages are ordered deterministically by day, project, environment, provider, model, endpoint and sub-account, so a cursor stays valid for the same query.
cursor=""
while :; do
page=$(curl -s "https://api.cencori.com/v1/usage/focus?start=2026-09-01&end=2026-10-01&cursor=$cursor" \
-H "Authorization: Bearer $CENCORI_USAGE_EXPORT_KEY")
echo "$page" | jq -c '.data[]' >> september.focus.jsonl
cursor=$(echo "$page" | jq -r '.next_cursor // empty')
[ -z "$cursor" ] && break
done
