Skip to main content

API tags

Tags are optional key-value metadata labels that can be attached to API credentials and other secrets for categorization, filtering, and cost attribution.

Overview

API tags enable you to:

  • Organize and categorize secrets (API keys, BYOK credentials, MCP tokens, and KEKs) by purpose, environment, team, or owner
  • Filter and search your credential inventory using tag key-value pairs
  • Attribute costs to specific applications, projects, cost centers, or business units
  • Enforce governance through policies that require or restrict certain tags
  • Track changes with audit logs that record tag modifications

Tags are stored as a map of key-value pairs, with both keys and values as strings. Each secret can have zero or more tags, and tag values are case-sensitive.

Supported resources

Tags are supported on Secrets across all realms:

RealmPurpose
llm-providersAPI keys for LLM providers (OpenAI, Anthropic, etc.)
byokBring Your Own Key credentials
mcpModel Context Protocol OAuth tokens
telemetryOpenTelemetry export credentials
kekKey encryption keys (system-level)

API operations

Create a secret with tags

Include a tags map in the request body when creating a secret:

curl -X POST https://api.example.com/v1/secrets \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "openai-prod-key",
"realm": "llm-providers",
"value": "sk-...",
"description": "OpenAI API key for production",
"tags": {
"app": "chatbot",
"environment": "production",
"cost-center": "engineering"
}
}'

Response:

{
"secret": {
"id": "sec_abc123...",
"name": "openai-prod-key",
"realm": "llm-providers",
"description": "OpenAI API key for production",
"tags": {
"app": "chatbot",
"environment": "production",
"cost-center": "engineering"
},
"createdAt": "2025-03-15T10:30:00Z",
"updatedAt": "2025-03-15T10:30:00Z",
"status": "SECRET_STATUS_ACTIVE"
}
}

Retrieve a secret with tags

Fetch a secret by name to view its tags:

curl -X GET https://api.example.com/v1/secrets/openai-prod-key \
-H "Authorization: Bearer $API_KEY"

The response includes the full tag set under the tags field.

List and filter secrets by tags

Query secrets using tag filters to retrieve only credentials matching specific criteria:

# Filter by a single tag key-value pair
curl -X GET "https://api.example.com/v1/secrets?tags.environment=production" \
-H "Authorization: Bearer $API_KEY"

# Filter by multiple tags (AND logic)
curl -X GET "https://api.example.com/v1/secrets?tags.environment=production&tags.app=chatbot" \
-H "Authorization: Bearer $API_KEY"

# Filter by realm and tags together
curl -X GET "https://api.example.com/v1/secrets?realm=llm-providers&tags.cost-center=engineering" \
-H "Authorization: Bearer $API_KEY"

Filtering uses AND logic: a secret matches only if all specified tag filters apply.

Update secret tags

Update a secret to modify its tags:

curl -X PATCH https://api.example.com/v1/secrets/openai-prod-key \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tags": {
"app": "chatbot",
"environment": "production",
"cost-center": "ai-operations",
"owner": "platform-team"
}
}'

All fields in the tags map replace the existing tags entirely (full replacement, not merge).

Rotate a secret (preserves tags)

When you rotate a secret, tags are preserved on the rotated version:

curl -X POST https://api.example.com/v1/secrets/openai-prod-key/rotate \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"newValue": "sk-..."}'

The rotated secret retains all tags from the previous version.

Delete a secret (removes tags)

When a secret is deleted, its associated tags are removed as well:

curl -X DELETE https://api.example.com/v1/secrets/openai-prod-key \
-H "Authorization: Bearer $API_KEY"

Use cases

Cost attribution and chargeback

Use tags to answer "What should this cost be booked against?" and enable team leads and finance to split spending reports by cost center, application, or business unit:

{
"tags": {
"cost-center": "engineering",
"app": "rag-pipeline",
"environment": "production"
}
}

When combined with cost reports, these tags enable you to answer questions such as:

  • Which applications consumed the most tokens in production?
  • What is the monthly spend per cost center?
  • Which teams should be charged for this quarter's API usage?

Environment and realm organization

Separate credentials by deployment environment:

{
"tags": {
"environment": "production",
"region": "us-west-2",
"team": "platform"
}
}

Compliance and audit

Tag secrets with compliance-relevant metadata for audit and regulatory purposes:

{
"tags": {
"pci-applicable": "true",
"soc2-audit": "required",
"data-classification": "confidential"
}
}

Policy-enforced tags

Define policies that require certain tags or restrict tag values to a governed set. This ensures consistent tagging practices and defensible cost attribution:

  • Require tags: A secret cannot be created or updated without certain required tags
  • Restrict values: A tag value must be from an enumerated, policy-defined list (e.g., environment must be one of dev, staging, production)

See Choose the right cost control for policy configuration details.

Tag design best practices

Use consistent naming conventions

Adopt standardized tag keys and values across your organization:

{
"environment": "production",
"cost-center": "engineering",
"owner": "platform-team",
"application": "chatbot"
}

Avoid inconsistently named keys (e.g., env vs environment, app vs application), which breaks filtering and analytics.

Keep tag values simple and enum-like

Restrict tag values to a small, known set of options when possible:

{
"environment": "dev|staging|production",
"team": "platform|data|infra|security",
"cost-center": "001|002|003"
}

Simple values are easier to filter, audit, and enforce in policies.

Limit the number of tags per secret

A reasonable limit is 5–10 tags per secret. Too many tags become unwieldy to manage and enforce.

Document your tag schema

Maintain a reference document or policy that describes:

  • The tag keys your organization uses
  • Allowed values for each key
  • The purpose and use case for each tag
  • Which tags are required vs optional
  • Governance rules (e.g., cost-center is required for production credentials)

Use lowercase and hyphens for keys

Follow a consistent naming scheme for tag keys:

{
"environment": "production",
"cost-center": "engineering",
"team-lead": "[email protected]"
}

This avoids confusion from mixed case (e.g., CostCenter vs cost-center vs costCenter).

Audit logging

Changes to secret tags are recorded in the audit log. Each action—create, update, rotate, or delete—captures:

  • What changed: Old and new tag values
  • Who changed it: User ID and authenticated entity
  • When: Timestamp
  • Resource: Secret ID and name
  • Context: Request ID, IP address, and other metadata

Use audit logs to:

  • Verify tag governance compliance
  • Investigate cost attribution disputes
  • Track credential lifecycle and ownership changes
  • Meet compliance and regulatory audit requirements

See Audit log events for the complete event reference.

Policy-based tag enforcement

The Admin Dashboard and policy engine can enforce tag governance by:

  1. Requiring tags before a secret can be created or updated
  2. Restricting values to a policy-defined enumeration
  3. Blocking creation or modification if required tags are missing or invalid

Example policy:

secretTags:
required:
- cost-center
- environment
allowedValues:
environment:
- dev
- staging
- production
cost-center:
- "001"
- "002"
- "003"

With this policy in place:

  • Every secret must include both cost-center and environment tags
  • environment must be one of dev, staging, or production
  • cost-center must be one of 001, 002, or 003
  • Requests that violate the policy receive a 400 Bad Request error with details

See the Admin Dashboard documentation for policy configuration.

SDK examples

Go

import "github.com/tetrateio/agent-router/sdk/go/agentrouter/secret/v1"

// Create a secret with tags
resp, err := secretClient.CreateSecret(ctx, &secret.CreateSecretRequest{
Name: "openai-prod-key",
Realm: "llm-providers",
Value: "sk-...",
Description: "OpenAI API key for production",
Tags: map[string]string{
"app": "chatbot",
"environment": "production",
"cost-center": "engineering",
},
})

// List secrets filtered by tags
listResp, err := secretClient.ListSecrets(ctx, &secret.ListSecretsRequest{
Realm: "llm-providers",
Tags: map[string]string{
"environment": "production",
},
})

Python

from agent_router.secret.v1 import secret_pb2, secret_service_pb2

# Create a secret with tags
request = secret_service_pb2.CreateSecretRequest(
name="openai-prod-key",
realm="llm-providers",
value="sk-...",
description="OpenAI API key for production",
tags={
"app": "chatbot",
"environment": "production",
"cost-center": "engineering",
}
)
response = client.CreateSecret(request)

# List secrets filtered by tags
request = secret_service_pb2.ListSecretsRequest(
realm="llm-providers",
tags={
"environment": "production",
}
)
response = client.ListSecrets(request)

TypeScript

import { SecretServiceClient } from '@agent-router/sdk';

// Create a secret with tags
const response = await secretClient.createSecret({
name: "openai-prod-key",
realm: "llm-providers",
value: "sk-...",
description: "OpenAI API key for production",
tags: {
app: "chatbot",
environment: "production",
"cost-center": "engineering",
},
});

// List secrets filtered by tags
const listResponse = await secretClient.listSecrets({
realm: "llm-providers",
tags: {
environment: "production",
},
});