Skip to content
Cloud Score Docs

Attribute cost to teams and apps

Tag every request with team, application, agent, environment, and end_user so Usage & cost can break spend down by them as reported tags, budgets can cap a team or an app, and alert rules can watch them.

WhereAnalyticsUsage & CostNeeds a gateway keyNeeds traffic on that keyOpen in Cloud Score
The Breakdown by table on Usage & cost: the dimension switch, then one row per team with AI spend, share, change against the previous period, requests, success, tokens, cache read, cost per request, and active users and agents.
The breakdown: switch the dimension, sort a column, and open a row for its drawer.
On this page

The five dimensions

Every request the gateway records carries up to five attribution values. Cloud Score resolves each one on its own, stores it on the request row, and reports it as a reported tag on Usage & cost. Values are trimmed and capped at 120 characters; a blank value means absent.

One metadata key and one header per dimension; three of the five can also default from the key.
Dimensionmetadata keyHeaderKey defaultExample value
TeamteamX-Dex-TeamThe Team field on the keysupport
ApplicationapplicationX-Dex-ApplicationThe Application field on the keyhelpdesk
AgentagentX-Dex-AgentNo field in the key dialogs; send it per requesttriage
EnvironmentenvironmentX-Dex-EnvironmentThe Environment field on the keyproduction
End userend_userX-Dex-End-UserNever; only a request can set itcustomer-8812; on the OpenAI-compatible endpoint the standard user field fills it

Reported tags are not assignments.

On Usage & cost, the Team, User and Agent dimensions come from the API key's assigned team and member when the request was admitted, and from the registered agent. The tags on this page are what the caller reported, read literally: Reported application, Reported environment and Reported end user. HTTP header names are not case sensitive, so X-Dex-team is the same header as X-Dex-Team.

Precedence

Request body metadata

metadata.{dimension} on either endpoint; compat user fills end_user

X-Dex-* headers

one header per dimension

The key's attribution defaults

set under Admin › API keys; never end_user

Left beats right, one dimension at a time. A request that sends only metadata.team still takes its application and environment from the key. A blank value counts as absent, so it never hides a lower source.

Send tags with a request

Both gateway endpoints accept a metadata object in the request body. Keys other than the five above are ignored, so your own tags can stay in it. On the native endpoint (see the native endpoint) it sits next to input and constraints:

POST /v1/requests
{
  "input": "Summarise this ticket thread for the on-call engineer.",
  "constraints": { "strategy": "cost" },
  "metadata": {
    "team": "support",
    "application": "helpdesk",
    "agent": "triage",
    "environment": "production",
    "end_user": "customer-8812"
  }
}

On the OpenAI-compatible endpoint (see the OpenAI-compatible endpoint) the same metadata object works and the standard user field maps to end_user. The Python · OpenAI-compatible snippet from Admin › Developer does not include metadata; add it yourself:

POST /v1/chat/completions
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudscore.internal:7001/v1",
    api_key=os.environ["DEX_API_KEY"],
)

res = client.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "Welcome a new customer in two sentences."}],
    user="customer-8812",
    metadata={"team": "growth", "application": "onboarding-bot"},
)

Headers are the option when you cannot touch the body, for example from a proxy or a shared SDK wrapper. Each header sets one dimension; anything the request does not name falls through to the key.

Tags as headers
curl -X POST "http://localhost:7001/v1/chat/completions" \
  -H "Authorization: Bearer $DEX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Dex-Team: support" \
  -H "X-Dex-Agent: triage" \
  -d '{"model": "auto", "messages": [{"role": "user", "content": "Summarise this ticket."}]}'

The native response envelope echoes what resolved as routing.attribution, so a client can confirm its tags landed without opening the dashboard.

Set defaults on a key

Defaults live on the API key under Admin › API keys (see API keys). They cover team, application, and environment, and apply to every request on the key that carries no value of its own for that dimension.

When creating a key:

  1. Click API keys under Admin in the sidebar, then Create key.

    The Create API key dialog opens.

  2. Give it a Name, for example helpdesk-prod.

  3. Under Cost attribution defaults (optional), fill Team, Application, and Environment.

    The helper reads Applied to requests on this key that carry no metadata or X-Dex-* tag of their own. Leave a field blank to set nothing for that dimension.

  4. Click Create, copy the key from Key created, then click Done.

    Only the non-blank fields are sent. The new row's Attribution column shows chips such as team=support.

On a key that already exists:

  1. In the API keys table, find the key's row.

    Its Attribution column shows chips team=…, application=…, environment=…, or — when nothing is stored.

  2. Open the row's ⋯ menu and click Edit tags.

    The Attribution — helpdesk-prod dialog opens with the same Cost attribution defaults (optional) block.

  3. Change the fields and click Save.

    The button reads Saving…, the dialog closes, and the chips refresh. A blank field drops that default. On failure the dialog shows the server message or save failed.

Tagging a key re-attributes its history.

Where attribution is read live (the operator default is ATTRIBUTION_FREEZE_READS=false), untagged requests read their key's current defaults, so Edit tagsmoves the key's whole untagged history under the new values. Optimizations follows the same rule. end_user never inherits.

Where attribution shows

Once requests carry tags, they appear as reported tags on Usage & cost, in Observability, in budgets and alert rules, and in the key table. Every place matches on the exact spelling you sent.

WhereLabelWhat you see
Usage & cost › Breakdown by, under MoreReported application, Reported environment, Reported end userOne row per value the callers sent, ranked by AI spend, with a drawer per row. Requests with no value group as Not reported, so the totals reconcile.
Usage & cost filter bar, under MoreReported application, Reported environment, Reported end user, Reported agent tagEach narrows every block to that exact value; Clear filters resets them. An old link that carries a team tag shows a Reported team tag chip, so it never widens to every team.
Observability › RequestsAgent, EnvironmentThe agent and environment each request reported, or — with its cause. The Request drawer shows the rest of its recorded attribution.
Admin › API keysAttributionThe key's stored defaults as chips team=…, application=…, environment=…, or —; Edit tags is in the row's ⋯ menu.
Budgets › Scoped LimitsTabs Teams, Users, Agent tags (legacy), Applications, EnvironmentsOne row per tag value with its limits; Edit limits sets them. Requests whose resolved value matches are admitted against that budget. See Budgets.
Budgets › Alerts, card Threshold rulesScope = team, application, agent, environment, or end userThe value input is labelled team value (and so on) whose empty-field hint reads exact value. The rule row then reads team: support. See Alerts.
Budgets › Alerts, card Recorded anomaliesRows such as team: supportThe hourly anomaly detector's rows, one per group per day.

Before any request carries a tag, the matching reported-tag dimension on Usage & cost shows a single Not reported row. A budget scope's tab says how to start, for example No team tags yet.

Examples

A key with defaults and a request that overrides team

What you do

The key helpdesk-prod has Edit tags defaults Team support, Application helpdesk, Environment production. One request on that key sends "metadata": {"team": "platform", "agent": "triage"}.

What Cloud Score does

Resolves each dimension separately: team platform (body beats the key), application helpdesk (key default), agent triage (body), environment production (key default), no end_user.

What you see

The native response's routing.attribution echoes team platform, application helpdesk, agent triage and environment production. On Usage & cost the request counts under helpdesk in Breakdown by Reported application, and the Reported agent tag chip set to triage finds it. A Teams budget on platformadmits it, while the key's other requests count against support.

Rolling attribution out to a key that already has traffic

What you do

Breakdown by Reported application shows only Not reported. You open Admin › API keys, click Edit tags on helpdesk-prod, set Team support, Application helpdesk, Environment production, and click Save.

What Cloud Score does

Stores the defaults on the key. Untagged requests on it, past and future, read those defaults at read time; requests that sent their own metadata or headers keep their own values.

What you see

New requests on the key report support, helpdesk and production, and budgets and alert rules on those values match them; where attribution is read live, the key's untagged history does too. Agent tags stay empty until clients send metadata.agent or X-Dex-Agent, and Reported end user until they send end_user or the compat user field.

Good to know

Agent has no field on the key.

The Create API key and Attribution — helpdesk-prod dialogs offer only Team, Application, and Environment. Send agent per request, in metadata or as X-Dex-Agent.

Spelling is the join key.

Breakdowns, filters, budget scopes, and alert rules all match the exact value. Support and support are two teams; a Teams budget on support caps only the requests that resolved to that spelling.

Limits

Values are trimmed and capped at 120 characters. Unknown metadata keys are ignored. end_user is never a key default. Budgets can scope to the workspace, an API key, a team, a user, an application, an agent tag, an environment, a registered agent or a provider; threshold rules can scope to end user too.

Filters and organization-wide figures

The reported-tag filters narrow every block on Usage & cost. On Optimizations, the Team, Application, Agent, Environment and End userfilters use the same rule, while Return on investment on ROI & Impact stays organization-wide. See Usage & cost and Costs, savings, and estimates.

Related