Python SDK Limit Tags API
Overview
This guide explains how to manage limit tags in Pay-i using the Python SDK. Limit tags provide a flexible way to categorize, organize, and filter your spending limits, helping you implement more sophisticated cost control strategies. For a conceptual understanding of limit tags and their role in the Pay-i platform, please refer to the Limit Tags page.
For a detailed API reference with complete parameter and return type information, see the Python SDK Limit Tags API Reference.
When to Use Limit Tags
You'll work with limit tags in the Pay-i Python SDK for several important purposes:
- Organization: Categorize limits by department, project, team, or business unit
- Filtering: Easily find and manage related limits by filtering on specific tags
- Billing Attribution: Track spending across organizational boundaries or cost centers
- Reporting: Generate spending reports segmented by custom business dimensions
- Lifecycle Management: Mark limits for specific time periods, initiatives, or campaigns
Limit Tags in the Pay-i Developer Portal
Tags can be assigned to limits in two ways:
- Programmatically through the Python SDK (as demonstrated in this guide)
- Directly through the Pay-i developer portal UI (as explained in the Limit Tags guide)
Once you've assigned tags to your limits, they become powerful organizational tools in the Pay-i developer portal:
- Tags appear as columns in the Limits management view, making it easy to identify limit purposes at a glance
- You can edit tags directly in the portal by selecting a limit and using the editing interface
- Tags become available as filters in dashboards and reports throughout the portal
- You can quickly filter limits by specific tags to analyze spending patterns across teams or projects
- Tags provide consistent organizing principles across your entire Pay-i implementation
This makes tags especially powerful for teams managing large numbers of limits, as they enable quick filtering in the UI without requiring additional API calls from your application.
Common Workflows
Working with the Pay-i limit tags API involves several common patterns for organizing and categorizing your spending limits. This section walks you through these workflows with practical code examples. While this guide demonstrates programmatic management of tags, all operations can also be performed through the Pay-i developer portal UI. When writing code that interacts with limits, remember that tags might change if other users modify them through the UI.
The examples below demonstrate how to:
- Create a limit with initial tags
- Add tags to existing limits
- View tags associated with a limit
- Update tags on a limit
- Remove tags from a limit
These examples build on each other to show a complete workflow, with each code snippet assuming you have initialized the client with your API key.
Note: These examples use the Python SDK's client objects (
Payi
andAsyncPayi
), which provide a resource-based interface to the Pay-i API. For details on client initialization and configuration, see the Pay-i Client Initialization guide.
Setting Up a Tagged Limit Structure
Let's start by creating a limit with initial tags to establish a foundation for our tagging system:
from payi import Payi
# Initialize the Pay-i client
client = Payi() # API key will be loaded from PAYI_API_KEY environment variable
# Step 1: Create a limit with initial tags
response = client.limits.create(
limit_name="Marketing Department Budget",
max=5000.0,
limit_type="block", # Block requests when limit is reached
threshold=0.80, # Notify at 80% of limit
limit_tags=["marketing", "department", "2024"]
)
# Step 2: Store the limit ID for future reference
# You'll need this ID to check status, update tags, or access the limit
limit = response.limit
stored_limit_id = limit.limit_id
print(f"Created '{limit.limit_name}' with tags: {limit.limit_tags}")
print(f"Limit ID: {stored_limit_id}")
Expected output:
Created 'Marketing Department Budget' with tags: ['marketing', 'department', '2024']
Limit ID: lim_1234567890
Viewing Limit Tags
After creating a limit with tags, you may need to view the tags associated with it:
# Step 3: View the tags on our new limit
response = client.limits.tags.list(limit_id=stored_limit_id)
if response.limit_tags:
print(f"Limit has {len(response.limit_tags)} tags: {', '.join(response.limit_tags)}")
else:
print("Limit has no tags")
Expected output:
Limit has 3 tags: marketing, department, 2024
Adding Tags to an Existing Limit
As your tagging strategy evolves, you'll often need to add new tags to existing limits:
# Step 4: Add campaign-specific tags to our existing limit
response = client.limits.tags.create(
limit_id=stored_limit_id,
limit_tags=["campaign_q2_2024", "social_media"]
)
print(f"Updated tags: {response.limit_tags}")
# Verify the new set of tags
updated_tags = client.limits.tags.list(limit_id=stored_limit_id)
print(f"Limit now has {len(updated_tags.limit_tags)} tags:")
for tag in updated_tags.limit_tags:
print(f" - {tag}")
Expected output:
Updated tags: ['marketing', 'department', '2024', 'campaign_q2_2024', 'social_media']
Limit now has 5 tags:
- marketing
- department
- 2024
- campaign_q2_2024
- social_media
Updating Tags
When your organizational structure changes, you may want to completely replace the existing tags with a new set:
# Step 5: Replace all existing tags with a new taxonomy
response = client.limits.tags.update(
limit_id=stored_limit_id,
limit_tags=["mktg", "digital", "2024_q2", "social_campaigns"]
)
print(f"Tags completely replaced. New tags: {response.limit_tags}")
Expected output:
Tags completely replaced. New tags: ['mktg', 'digital', '2024_q2', 'social_campaigns']
Removing Tags
When campaigns end or priorities shift, you may need to remove specific tags while keeping others:
# Step 6: Remove specific tags that are no longer relevant
response = client.limits.tags.remove(
limit_id=stored_limit_id,
limit_tags=["2024_q2"] # Remove just the quarterly tag
)
print(f"After removing '2024_q2': {response.limit_tags}")
# Step 7: In some cases, you might want to clear all tags
clear_response = client.limits.tags.delete(limit_id=stored_limit_id)
print(f"All tags removed. Current tags: {clear_response.limit_tags}")
Expected output:
After removing '2024_q2': ['mktg', 'digital', 'social_campaigns']
All tags removed. Current tags: []
Note: For more detailed guidance on when to remove tags versus when to delete limits entirely, see the Tag Management Best Practices section later in this guide.
Finding and Filtering Limits by Tags
One of the main benefits of tags is the ability to find and group limits based on their tags. Let's explore this powerful capability:
# Step 8: Create several limits with a consistent tagging strategy
departments = ["marketing", "engineering", "sales", "support"]
dept_limit_ids = {}
for department in departments:
response = client.limits.create(
limit_name=f"{department.capitalize()} Department Budget",
max=10000.0,
limit_type="allow", # For monitoring purposes
threshold=0.85,
limit_tags=[department, "department", "2024_budget"]
)
dept_limit_ids[department] = response.limit.limit_id
print(f"Created {department} budget with id: {response.limit.limit_id}")
# Step 9: Find all limits with a specific tag
all_limits = client.limits.list()
department_limits = [limit for limit in all_limits if hasattr(limit, "limit_tags") and "department" in limit.limit_tags]
print(f"\nFound {len(department_limits)} limits with the 'department' tag:")
for limit in department_limits:
print(f" {limit.limit_name}: {limit.limit_tags}")
Expected output:
Created marketing budget with id: lim_1234567891
Created engineering budget with id: lim_1234567892
Created sales budget with id: lim_1234567893
Created support budget with id: lim_1234567894
Found 4 limits with the 'department' tag:
Marketing Department Budget: ['marketing', 'department', '2024_budget']
Engineering Department Budget: ['engineering', 'department', '2024_budget']
Sales Department Budget: ['sales', 'department', '2024_budget']
Support Department Budget: ['support', 'department', '2024_budget']
Adapting Tags to Organizational Changes
When your organization evolves, your tagging strategy should adapt. For example, during a department restructuring:
# Step 10: After a department reorganization, update tags
client.limits.tags.update(
limit_id=dept_limit_ids["marketing"],
limit_tags=["marketing", "digital_marketing_team", "2024_reorganization"]
)
# Verify the updated tags
updated_tags = client.limits.tags.list(limit_id=dept_limit_ids["marketing"])
print(f"Marketing department's new tags: {updated_tags.limit_tags}")
Expected output:
Marketing department's new tags: ['marketing', 'digital_marketing_team', '2024_reorganization']
Real-World Example: Implementing a Cost Allocation System
Let's pull everything together into a comprehensive end-to-end example of implementing a cost allocation system using limit tags to track spending across different departments and projects.
from payi import Payi
import datetime
# Initialize the Pay-i client
client = Payi()
print("---- Building a Cost Allocation System with Pay-i Limit Tags ----")
# Step 1: Set up department budgets with consistent tagging scheme
def setup_department_budgets():
print("\nš Setting up department budgets...")
departments = {
"marketing": 5000.0,
"engineering": 10000.0,
"product": 7500.0,
"research": 8000.0
}
current_quarter = f"q{(datetime.datetime.now().month-1)//3+1}_{datetime.datetime.now().year}"
limit_ids = {}
for dept, budget in departments.items():
# Create a limit with department tags
response = client.limits.create(
limit_name=f"{dept.capitalize()} Department Budget",
max=budget,
limit_type="allow", # For tracking purposes
threshold=0.80,
limit_tags=[dept, "department", current_quarter]
)
limit_ids[dept] = response.limit.limit_id
print(f" Created {dept} budget: ${budget:.2f}, ID: {response.limit.limit_id}")
return limit_ids
# Step 2: Add project tags to department limits
def tag_projects_to_departments(dept_limit_ids):
print("\nš·ļø Adding project-specific tags to each department...")
# Marketing projects
marketing_tags = ["social_campaign", "content_production", "analytics"]
print(f" Adding to marketing: {marketing_tags}")
client.limits.tags.create(
limit_id=dept_limit_ids["marketing"],
limit_tags=marketing_tags
)
# Engineering projects
engineering_tags = ["backend_api", "frontend_redesign", "infrastructure"]
print(f" Adding to engineering: {engineering_tags}")
client.limits.tags.create(
limit_id=dept_limit_ids["engineering"],
limit_tags=engineering_tags
)
# Get updated tags for verification
for dept, limit_id in dept_limit_ids.items():
tags = client.limits.tags.list(limit_id=limit_id).limit_tags
print(f" {dept} department tags: {tags}")
# Step 3: Track usage against tagged limits
def track_usage_with_tags(dept_limit_ids):
print("\nš Recording AI usage against tagged department limits...")
# Simulate usage for different departments and projects
for dept, limit_id in dept_limit_ids.items():
if dept == "marketing":
# Track social media campaign costs
client.ingest.units(
category="system.openai",
resource="gpt-4o-2024-05-13",
units={"text": {"input": 10000, "output": 5000}},
limit_ids=[limit_id],
metadata={"project": "social_campaign"}
)
print(f" Recorded usage for {dept} - social_campaign")
elif dept == "engineering":
# Track API development costs
client.ingest.units(
category="system.openai",
resource="gpt-4o-2024-05-13",
units={"text": {"input": 20000, "output": 8000}},
limit_ids=[limit_id],
metadata={"project": "backend_api"}
)
print(f" Recorded usage for {dept} - backend_api")
# Step 4: Generate a spending report by department
def generate_spending_report(dept_limit_ids):
print("\nš Generating spending report by department...")
print("-----------------------------")
total_spent = 0
for dept, limit_id in dept_limit_ids.items():
limit = client.limits.retrieve(limit_id=limit_id).limit
spent = limit.totals.cost.total.base
total_spent += spent
budget = limit.max
usage_pct = (spent / budget) * 100 if budget > 0 else 0
print(f" {dept.capitalize()}: ${spent:.2f} of ${budget:.2f} budget ({usage_pct:.1f}%)")
print(f"\n Total company spending: ${total_spent:.2f}")
# Execute the workflow
dept_limit_ids = setup_department_budgets()
tag_projects_to_departments(dept_limit_ids)
track_usage_with_tags(dept_limit_ids)
generate_spending_report(dept_limit_ids)
print("\nā
Cost allocation system implementation complete!")
Expected output:
---- Building a Cost Allocation System with Pay-i Limit Tags ----
š Setting up department budgets...
Created marketing budget: $5000.00, ID: lim_2224
Created engineering budget: $10000.00, ID: lim_2225
Created product budget: $7500.00, ID: lim_2226
Created research budget: $8000.00, ID: lim_2227
š·ļø Adding project-specific tags to each department...
Adding to marketing: ['social_campaign', 'content_production', 'analytics']
Adding to engineering: ['backend_api', 'frontend_redesign', 'infrastructure']
marketing department tags: ['marketing', 'department', 'q2_2024', 'social_campaign', 'content_production', 'analytics']
engineering department tags: ['engineering', 'department', 'q2_2024', 'backend_api', 'frontend_redesign', 'infrastructure']
product department tags: ['product', 'department', 'q2_2024']
research department tags: ['research', 'department', 'q2_2024']
š Recording AI usage against tagged department limits...
Recorded usage for marketing - social_campaign
Recorded usage for engineering - backend_api
š Generating spending report by department...
-----------------------------
Marketing: $1.75 of $5000.00 budget (0.0%)
Engineering: $3.28 of $10000.00 budget (0.0%)
Product: $0.00 of $7500.00 budget (0.0%)
Research: $0.00 of $8000.00 budget (0.0%)
Total company spending: $5.03
ā
Cost allocation system implementation complete!
This comprehensive example demonstrates how to:
- Create department-level budgets with consistent tagging
- Add project-specific tags to each department budget
- Track usage against those tagged limits
- Generate spending reports by department
Understanding Tag Behavior
When working with limit tags, it's important to understand their relationship with limits:
- Tags are attributes of limits, providing a way to categorize and filter them
- When you modify tags, you're changing how current and historical usage data can be filtered
- Changing a limit's tags affects all past and future data associated with that limit
For example, if you have six months of usage data associated with a limit tagged "marketing," and you then remove that tag, those historical records won't appear in searches for "marketing" tagged limits.
Tag Management Best Practices
As your usage of limits and tags evolves, you'll need to make decisions about managing your tagging structure. There are two distinct operations to consider:
When to Remove Tags vs. When to Delete Limits
Removing Tags (using remove()
or update()
) is appropriate when:
- A specific classification is no longer relevant (e.g., a campaign has ended)
- You're reorganizing your tagging scheme while keeping the limits active
- You want to maintain the limit and its history but update its categorization
- Tags were applied incorrectly and need correction
# Remove campaign-specific tags at the end of a quarter
client.limits.tags.remove(
limit_id="lim_1234567890",
limit_tags=["q2_2024"] # Just remove the quarterly tag
)
Deleting Limits based on tags requires more careful consideration:
- This is a destructive operation that removes the entire limit, not just the tags
- Any limits deleted will no longer track usage or enforce spending limits
- All historical data and configuration associated with those limits is lost
Cleaning Up Orphaned or Testing Limits
When working with tags, you'll often encounter scenarios where you need to clean up limits that were created for testing, development, or temporary purposes. The most effective strategy is to use a designated "cleanup" tag (like "temp" or "test") for limits that are meant to be temporary.
This function demonstrates how to safely delete only those limits that have a single specific tag and no other tags. This is particularly useful for:
- Cleaning up testing or development limits without affecting production limits
- Removing temporary limits that were created for specific experiments
- Performing maintenance tasks that target only "orphaned" limits
- Implementing a tag-based lifecycle policy (e.g., automatically deleting limits tagged only as "deprecated")
By targeting only limits with a single tag, you ensure that multi-tagged limits that serve multiple purposes are preserved. This is much safer than batch-deleting all limits with a certain tag, as that approach might inadvertently remove limits that are still needed for other purposes.
This approach is particularly valuable in automated environments, where scripts in CI/CD pipelines might create numerous temporary limits during testing, QA, or staging processes. Using the SDK in these scenarios provides a programmatic way to clean up environment-specific limits that would be impractical to manage through the UI.
# Function to safely delete limits that have ONLY the specified tag
def delete_limits_with_single_tag(tag, require_confirmation=True):
"""Delete limits that have ONLY the specified tag and no other tags."""
# First, identify all limits with the tag
all_limits = client.limits.list()
matching_limits = [limit for limit in all_limits
if hasattr(limit, "limit_tags") and tag in limit.limit_tags]
if not matching_limits:
print(f"No limits found with tag: {tag}")
return
# Filter to only limits that have exactly one tag (the specified tag)
single_tag_limits = []
multi_tag_limits = []
for limit in matching_limits:
if len(limit.limit_tags) == 1:
single_tag_limits.append(limit)
else:
multi_tag_limits.append(limit)
# Summary of what was found
print(f"Found {len(matching_limits)} limits with tag '{tag}':")
print(f" - {len(single_tag_limits)} limits with ONLY the '{tag}' tag")
print(f" - {len(multi_tag_limits)} limits with multiple tags (will be preserved)")
if not single_tag_limits:
print(f"No limits found with just the '{tag}' tag. Nothing to delete.")
return
# List the limits that would be deleted
print("\nLimits that will be deleted:")
for limit in single_tag_limits:
print(f" - {limit.limit_name} (ID: {limit.limit_id})")
# List the limits that will be preserved
if multi_tag_limits:
print("\nLimits that will be preserved (have multiple tags):")
for limit in multi_tag_limits:
other_tags = [t for t in limit.limit_tags if t != tag]
print(f" - {limit.limit_name} (ID: {limit.limit_id})")
print(f" Also tagged with: {other_tags}")
# Confirmation step
if require_confirmation:
confirmation = input(f"\nType 'DELETE' to confirm deletion of {len(single_tag_limits)} limits: ")
if confirmation != "DELETE":
print("Deletion cancelled")
return
# Proceed with deletion
deleted_count = 0
for limit in single_tag_limits:
try:
client.limits.delete(limit_id=limit.limit_id)
print(f"ā
Deleted: {limit.limit_name} (ID: {limit.limit_id})")
deleted_count += 1
except Exception as e:
print(f"ā Error deleting {limit.limit_name}: {str(e)}")
print(f"\nDeleted {deleted_count} limits that had only the '{tag}' tag")
print(f"Preserved {len(multi_tag_limits)} limits with multiple tags")
# Example usage:
# delete_limits_with_single_tag("test", require_confirmation=True)
For conceptual information about limit tags and how they can be used to categorize and organize your limits, see Limit Tags.
API Reference
For detailed information on all the methods, parameters, and response types provided by the client.limits.tags
resource, please refer to the Python SDK Limit Tags API Reference.
The reference documentation includes:
- Complete method signatures with all parameters
- Return type structures for all response types
- Detailed explanations of parameter behavior
- REST API endpoint mappings
- Examples for each method
This separate reference guide complements the workflow examples provided in this document, offering a more technical and comprehensive view of the limit tags API.
Updated 8 days ago