Skip to main content
Version: Dev

Cost Attribution Tags

Cost attribution tags let an organization charge usage and cost to its own dimensions, such as departments, business groups, subsidiaries, projects, or cost centers. The organization declares the tag keys, then sets key=value pairs on caller API keys, teams, and members. Every request is attributed to the tag values it resolves when it runs. The Cost Analysis page then breaks down spend by those values, tag budgets cap it, and rate limit policies can match and split traffic on it.

Tags work the same way in AISIX Enterprise and AISIX Cloud.

Prerequisites​

Before starting, prepare the following:

  • The owner or admin role in the organization, or a custom role with tag_keys write permission, to declare tag keys. Setting tags on a resource needs write permission on that resource.
  • A gateway that records tags on its usage in every environment that should be attributed. A gateway at 1.6.x or earlier does not; see Gateway Version Requirements.
  • For the Admin API examples, the control-plane URL and an admin token with write scope:
# AISIX_CP includes /api and has no trailing slash.
# The local AISIX Enterprise quickstart uses http://localhost:8080/api.
export AISIX_CP="YOUR_AISIX_CONTROL_PLANE_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export TEAM_ID="YOUR_TEAM_ID"
export ENV_ID="YOUR_ENVIRONMENT_ID"

Declare Tag Keys​

A tag key must be declared in the organization before any resource can carry it. Declaring keys up front keeps the vocabulary consistent, so department is never also spelled dept or Department.

  1. Open Tag Keys in the organization navigation, then select New tag key.
  2. Enter the Key, such as department.
  3. Optionally enter a Display name and a Description.
  4. Select Declare key.

To declare a key through the Admin API:

curl -sS -X POST "${AISIX_CP}/tag_keys" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"key": "department",
"display_name": "Department",
"description": "Cost center the usage is charged to."
}'

Tag keys follow these rules:

  • A key starts with a lowercase letter and contains only lowercase letters, digits, and underscores, up to 63 characters: ^[a-z][a-z0-9_]{0,62}$.
  • A key cannot be changed after it is declared. The display name and description can be edited at any time.
  • An organization can declare at most 32 keys. A request to declare one more returns 400 with the code TAG_KEY_LIMIT, and declaring a key that already exists returns 409.
  • Every member can read the declared keys. Writing them takes the tag_keys write permission.

Delete a Tag Key​

Deleting a tag key is refused with 409 and the code TAG_KEY_IN_USE while a budget or a rate limit policy uses it. The error message names them; remove them first.

Otherwise, the deletion removes the key from every caller API key, team, and member that carries it, and later requests are no longer attributed to it. Usage already recorded keeps the tags it was attributed with, so the deleted key's values still appear in the stored history. Cost Analysis keeps offering the key, marked Deleted, for any time range whose usage carries it.

Set Tags on API Keys, Teams, and Members​

Tags can be set on three resources. Each one carries its own tags, as an object of tag key to tag value:

ResourceDashboardAdmin API
Caller API keyThe Cost-attribution tags section of the key's create and edit forms, under the environment's API keysPOST /environments/{environment_id}/api_keys and PATCH /environments/{environment_id}/api_keys/{api_key_id}
TeamThe team's create and edit forms, under TeamsPOST /teams and PATCH /teams/{team_id}
MemberThe Tags panel on a member row in Members, and the Create user form in AISIX EnterprisePOST /members and PATCH /members/{user_id}

The dashboard offers the declared keys and suggests values the organization already uses for the selected key. The same suggestions are available from GET /tag_keys/{key}/values, which lists up to 500 distinct values currently set on caller API keys, teams, and members. Values that appear only in recorded usage are not included.

Tag values follow these rules:

  • A value is free-form text of 1 to 128 characters.
  • A value cannot contain control characters, such as a line break, and cannot start or end with whitespace, including non-breaking and full-width spaces. The control plane rejects such a value with 400.
  • Every key in a resource's tags must be declared in the organization.

In the Admin API, PATCH replaces the whole tags object. Send the complete set you want to keep. Send null or {} to clear every tag, and omit tags to leave them unchanged. For example, the following request sets two tags on a team:

curl -sS -X PATCH "${AISIX_CP}/teams/${TEAM_ID}" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"tags": {
"department": "rnd",
"subsidiary": "emea"
}
}'

A member's tags belong to their membership in this organization, not to their account. An admin can change a member's tags; changing a member's role still requires an owner. Members who join through an invitation, single sign-on, or SCIM directory sync start without tags. Tags of a member managed by directory sync can be edited in the dashboard and through the Admin API. Directory sync neither reads nor writes them, so tags are not synced from an identity provider.

How a Request Resolves Its Tags​

When a request authenticates, the gateway resolves its tags from the caller API key that authenticated it. For each tag key, the nearest value wins:

  1. The caller API key's own value.
  2. Otherwise, the value set on the team that the key is bound to.
  3. Otherwise, the value set on the member that owns the key.

Only the key's own team and member binding count. The other teams a member belongs to do not contribute any tags. A request carries one value per tag key, and different keys combine, so one request can take department from its key, business_group from its team, and subsidiary from its member. A request cannot supply its own tags; the gateway never reads them from request headers or the body.

For example, suppose the organization declares department, business_group, and subsidiary, and sets the following:

ResourceTags
Team platformdepartment=infra, business_group=cloud
Member Alicedepartment=rnd, subsidiary=emea
Key K1, bound to platform and owned by Alicedepartment=ml
Key K2, bound to platform and owned by AliceNone
Key K3, owned by Alice, with no teamNone

Requests resolve these tags:

Keydepartmentbusiness_groupsubsidiary
K1ml, from the keycloud, from the teamemea, from the member
K2infra, from the teamcloud, from the teamemea, from the member
K3rnd, from the memberNot setemea, from the member

Attribution Is Fixed When the Request Runs​

The gateway records the resolved tags and the key's team on every usage event of the request, including retries, failovers, and the gateway's own rejections. The control plane stores them with the event and attributes cost by what was recorded.

So a change to tags applies to later requests only. Changing a key's, team's, or member's tags, binding a key to another team, or deleting a tag key does not re-attribute usage that was already recorded. Usage recorded before a tag was set, and usage reported by a gateway that does not record tags, has no value for that tag and appears as Not set.

Analyze Cost by Tag​

The organization-level Cost Analysis page groups usage from every environment in the organization by one dimension at a time. The page has two sections: Filter selects the usage to analyze, and Statistics breaks it down. Work in that order: narrow the usage first, then group what is left, then drill down. For example, filter on business_group=cloud, then group by the department tag to see how that business group's spend splits across departments.

The Filter section comes first:

  • Time range: the last 24 hours, 7 days, or 30 days, or a custom range. The page reads whole hours, so the start is rounded down and the end up to the hour.
  • Filters: environments, team, member, model, and any number of tag key=value filters. Filters on different tag keys must all match, and several values of one key match any of them. A drill-down from an API key row adds that key as a filter. Each active filter shows as a chip below the controls, and Clear filters removes them all.

The Statistics section then breaks the filtered usage down:

  • Group by: a tag key, team, member, API key, model, environment, or day. Grouping by day shows a daily bar chart; other groupings show horizontal bars.
  • Sort by: cost, total tokens, input tokens, output tokens, requests, or successful requests. Groups are listed largest first.
  • Refresh: reloads the figures, together with the tag keys and the names of teams, members, and environments.

Select a row to drill down. The row's group becomes a filter, and the page picks the next grouping that the filters do not pin yet. The breadcrumb above the table returns to any earlier step. The Not set row collects usage that has no value for the grouping and cannot be drilled into. Day rows cannot be drilled into either. The table lists up to 50 groups; the rest are summed into an Other N groups row, so the listed groups and that row add up to the total.

When grouping by team or by a tag key, a Budget (current period) column shows the matching team or tag budget's current-period spend and limit. When grouping by API key, each key row links to the request logs of the environment the key belongs to, filtered to that key.

The tag keys offered in Group by, the tag filter, and drill-down are the organization's declared keys, plus any key that usage in the selected time range carries but that is no longer declared. Such a key was deleted after that usage was recorded. It is marked Deleted and can still be grouped and filtered on. Value suggestions come from the caller API keys, teams, and members that carry a key now, so a deleted key has none: type the value, or drill down from a group row. When there are no tag keys at all, the Group by and filter dropdowns show a hint with a link to the tag-keys settings, and the tag filter is unavailable until you declare tag keys.

A team, member, API key, or environment deleted after its usage was recorded still has its own row. Group rows, chart labels, the breadcrumb, and filter chips show it as the first 8 characters of its ID with a Deleted badge, or Removed for a member who is no longer in the organization. Select the badge to see the full ID and copy it. A Name unavailable badge means the console could not confirm whether the resource still exists, for example because the list of teams failed to load; it does not mean the resource was deleted.

After a control-plane upgrade, the page shows the same backfill notice as the Usage view while usage recorded before the upgrade is added, and the figures are incomplete until it finishes. Cost is in the organization's currency.

Every member with permission to read usage can open Cost Analysis. Automation reads the same figures from GET /usage_analysis, and the tag keys that usage in a time range carries, deleted keys included, from GET /usage_analysis/tag_keys; see the AISIX Enterprise / Cloud Admin API.

Budget by Tag​

A tag budget caps the spend attributed to one tag value across every environment in the organization. In the Budgets view, select the Tag scope, then select the tag key and enter the value. In the Admin API, set scope to tag and scope_ref to <key>=<value>, such as department=rnd. The key must be declared, and the value is everything after the first =. limit_cents is in the minor unit of the organization's currency.

curl -sS -X POST "${AISIX_CP}/budgets" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"display_name": "R&D monthly",
"scope": "tag",
"scope_ref": "department=rnd",
"limit_cents": 50000,
"period": "month",
"hard_stop": true
}'

A tag budget follows the same period, hard stop, and alert rules as other budgets, and a tag value can hold one budget. Spend is counted from the tags recorded on each request's usage. A hard-stop tag budget that has reached its limit rejects later requests that resolve the same tag value with 429 and the code budget_exceeded, with scope set to tag and scope_ref set to the key=value pair.

Creating a tag budget is refused with 422 and the code DP_INCOMPATIBLE while any registered gateway in any environment of the organization runs a release that does not record tags, which is 1.6.x or earlier. Such a gateway's usage would not count toward the budget.

Rate-Limit by Tag​

A conditional rate limit policy accepts tag:<key> as a condition dimension and in group_by. The key must be declared. For example, the following policy gives each department its own limit of 600 requests per minute:

curl -sS -X POST "${AISIX_CP}/environments/${ENV_ID}/rate_limits" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "per-department-rpm",
"group_by": ["tag:department"],
"limits": { "rpm": 600 }
}'

Two caller API keys that resolve department=rnd share one counter, and a key that resolves department=sales has its own. A request without a value for the tag does not match a condition on it, even a negated one, and is not subject to a policy that groups by it.

Saving a policy that uses tag: is refused with 422 and the code DP_INCOMPATIBLE while any registered gateway in that environment runs 1.6.x or earlier, because those releases cannot load it.

Read Tags in Usage Events and Request Logs​

Every usage event carries tags, the request's resolved tags, and team_id, the team the caller API key is bound to. Both are omitted when empty. Observability exporters deliver them to external systems, and Request Logs shows them in the row detail and in exports. See Attribute Events to a Team and Tags for the field names in each exporter. Tags never become Prometheus metric labels.

Gateway Version Requirements​

Tags are resolved and recorded by the gateway. A gateway at 1.6.x or earlier ignores them:

  • It loads tagged caller API keys, teams, and members, but ignores the tags field. The dashboard shows a partial-compatibility notice for those gateways.
  • Its usage carries no tags and no team_id, so it appears as Not set in Cost Analysis.
  • It drops a rate limit policy that uses tag:.

The control plane refuses to save tag budgets and tag rate limit policies while such a gateway is registered, as described above. That check can only see the gateways registered when the budget or policy is saved.

Known gap

If a gateway is rolled back to 1.6.x, or a 1.6.x gateway joins after a tag rate limit policy or tag budget was saved, tag rate limits are not enforced on that gateway and its usage is not counted toward tag budgets. The console's rejected-resources report shows it. Upgrade the gateway to restore enforcement and counting.

Next Steps​

Use Budgets and Budget Alerts and Notifications to cap and monitor tag spend. To compare tagged usage with environment-level totals, see Usage Reporting.