# Working with the Usage Groups API

URL: https://select.dev/docs/reference/api-reference/working-with-the-usage-groups-api
Index of all SELECT docs: https://select.dev/docs/llms.txt

> A full guide to programmatically creating and managing Usage Groups in Snowflake using the SELECT Usage Groups API, with examples, best practices, and troubleshooting tips.

While we recommend managing Usage Groups on an ongoing basis via our official Terraform provider, we recognize that not all teams use Terraform or there may be use cases where you want to programmatically create Usage Groups as a one-off.

For example, imagine you want to create a Usage Group per department using a series of object tags you have stored in Snowflake. Alternatively, imagine you have a customer-facing product built on top of Snowflake and want to create a Usage Group for each customer.

The guide below shows how you could accomplish that using our official Usage Groups API.

## **Prerequisites**

### **Step 1: Create an API Key**

To interact with the SELECT API, you'll need to generate an API key and get your organization ID from the SELECT app. Follow the [API quickstart instructions](https://api-docs.select.dev/v2/introduction) to get started.

Your API key must have the `usage_groups:write` scope and access to the appropriate Snowflake account(s) or organization(s).

## **Exploring Filter Options**

**🎯 Before diving into the API, we strongly recommend exploring filter options through the SELECT UI or Terraform documentation:**

### **Option 1: Use the SELECT UI (Recommended)**

1. Navigate to your Usage Groups page in the SELECT app
2. Click "Create Usage Group" or edit an existing one
3. Build your filter expression using the interactive filter builder
4. Click the "Interactive" toggle and switch to "JSON" mode
5. Copy the `filter_expression` field - this is exactly what you'll use in the API!

### **Option 2: Browse Terraform Examples**

Visit our [Terraform provider documentation](https://registry.terraform.io/providers/get-select/select/latest/docs/resources/usage_group) for comprehensive filter examples and available dimensions.

### **Option 3: Check Available Dimensions**

The available filter dimensions depend on whether your usage group set is scoped to an account or organization:

**Account-Scoped Dimensions** (most common):

- `warehouse_name`, `user_name`, `role_name`
- `warehouse_tags`, `user_tags`, `role_tags`, `database_tags`
- `resource_type`, `database_schema_name`
- And many more...

**Organization-Scoped Dimensions**:

- `account_name`, `region`, `service_level`, `usage_type`
- `account_name_and_usage_type`, `account_name_and_warehouse`

## **Complete API Workflow**

### **Step 1: Test Your API Credentials**

```python
import requests
import json

organization_id = "your_organization_id_here"  # Get from SELECT app
api_key = "sl_your_api_key_here"  # Generated from SELECT app

url = f"https://api.select.dev/api/{organization_id}/usage-group-sets"
headers = {"x-api-key": api_key}

# Test credentials by listing existing usage group sets
response = requests.get(url, headers=headers)
if response.status_code == 200:
    print("✅ API credentials working!")
    print("Existing usage group sets:", response.json())
else:
    print(f"❌ API Error: {response.status_code} - {response.text}")
    exit(1)

```

### **Step 2: Create a Usage Group Set (if needed)**

```python
# Create a usage group set scoped to a Snowflake account
usage_group_set_payload = {
    "name": "Department Cost Allocation",
    "order": 1,
    "snowflake_account_uuid": "your_snowflake_account_uuid_here"
    # OR use: "snowflake_organization_name": "your_org_name"
}

response = requests.post(url, headers=headers, json=usage_group_set_payload)
if response.status_code == 200:
    usage_group_set = response.json()
    usage_group_set_id = usage_group_set["id"]
    print(f"✅ Created usage group set: {usage_group_set_id}")
else:
    print(f"❌ Error creating usage group set: {response.text}")
    # You might want to use an existing set instead
    usage_group_set_id = "existing_set_id_here"

```

### **Step 3: Design Your Usage Group Mappings**

Create your mappings based on your business needs:

```python
# Example 1: Department-based allocation using warehouse names
department_mappings = [
    {
        "name": "Finance Department",
        "warehouse_names": ["FINANCE_WH", "FINANCE_ANALYTICS_WH"],
        "budget": 5000,
        "order": 1
    },
    {
        "name": "Marketing Department",
        "warehouse_names": ["MARKETING_WH", "CAMPAIGN_WH"],
        "budget": 3000,
        "order": 2
    }
]

# Example 2: Customer-based allocation using database tags
# (You'd get this from your customer database/CRM)
customer_mappings = [
    {
        "name": "Customer: Acme Corp",
        "database_tag_key": "customer_id",
        "database_tag_value": "acme_corp",
        "budget": 2000,
        "order": 1
    },
    {
        "name": "Customer: Beta Inc",
        "database_tag_key": "customer_id",
        "database_tag_value": "beta_inc",
        "budget": 1500,
        "order": 2
    }
]

```

### **Step 4: Create Filter Expressions**

**💡 Pro Tip**: Build your first filter in the SELECT UI, then copy the JSON structure!

```python
def create_warehouse_filter(warehouse_names):
    """Create a filter for specific warehouse names"""
    return {
        "operator": "or",
        "filters": [
            {
                "field": "warehouse_name",
                "operator": "in",
                "values": warehouse_names
            }
        ]
    }

def create_database_tag_filter(tag_key, tag_value):
    """Create a filter for database tags"""
    return {
        "operator": "or",
        "filters": [
            {
                "field": "database_tags",
                "operator": "array_contains",
                # Note: The format for filter on tags is
                # 'TagKey: TagValue'
                "values": [f"{tag_key}: {tag_value}"]
            }
        ]
    }

def create_user_pattern_filter(user_patterns):
    """Create a filter for user name patterns"""
    return {
        "operator": "or",
        "filters": [
            {
                "field": "user_name",
                "operator": "like",
                "values": user_patterns
            }
        ]
    }

# Example: Complex filter combining multiple criteria
def create_complex_filter():
    """Example of a more complex filter"""
    return {
        "operator": "and",
        "filters": [
            {
                "operator": "or",
                "filters": [
                    {
                        "field": "warehouse_name",
                        "operator": "in",
                        "values": ["ANALYTICS_WH", "REPORTING_WH"]
                    }
                ]
            },
            {
                "operator": "or",
                "filters": [
                    {
                        "field": "user_name",
                        "operator": "like",
                        "values": ["analytics_%", "report_%"]
                    }
                ]
            }
        ]
    }

```

### **Step 5: Create Usage Groups Programmatically**

```python
usage_groups_url = f"{url}/{usage_group_set_id}/usage-groups"

def create_usage_group(name, filter_expression, budget, order):
    """Helper function to create a usage group"""
    payload = {
        "name": name,
        "budget": budget,
        "order": order,
        "usage_group_set_id": usage_group_set_id,
        "filter_expression": filter_expression
    }

    response = requests.post(usage_groups_url, headers=headers, json=payload)

    if response.status_code == 200:
        print(f"✅ Created usage group: {name}")
        return response.json()
    else:
        print(f"❌ Error creating {name}: {response.text}")
        return None

# Create department-based usage groups
for dept in department_mappings:
    filter_expr = create_warehouse_filter(dept["warehouse_names"])
    create_usage_group(
        name=dept["name"],
        filter_expression=filter_expr,
        budget=dept["budget"],
        order=dept["order"]
    )

# Or create customer-based usage groups
for customer in customer_mappings:
    filter_expr = create_database_tag_filter(
        customer["database_tag_key"],
        customer["database_tag_value"]
    )
    create_usage_group(
        name=customer["name"],
        filter_expression=filter_expr,
        budget=customer["budget"],
        order=customer["order"]
    )

```

### **Step 6: Managing Existing Usage Groups**

Check for existing usage groups before creating new ones:

```python
def get_existing_usage_groups():
    """Get all existing usage groups in the set"""
    response = requests.get(usage_groups_url, headers=headers)
    if response.status_code == 200:
        return {group["name"]: group for group in response.json()}
    return {}

def smart_create_usage_groups(mappings, filter_func):
    """Only create usage groups that don't already exist"""
    existing = get_existing_usage_groups()

    for mapping in mappings:
        if mapping["name"] in existing:
            print(f"⏭️  Usage group '{mapping['name']}' already exists, skipping")
            continue

        filter_expr = filter_func(mapping)
        create_usage_group(
            name=mapping["name"],
            filter_expression=filter_expr,
            budget=mapping["budget"],
            order=mapping["order"]
        )

# Usage
smart_create_usage_groups(
    department_mappings,
    lambda dept: create_warehouse_filter(dept["warehouse_names"])
)

```

## **Real-World Examples**

### **Example 1: Multi-Tenant SaaS Application**

```python
# Create usage groups for each customer tenant
def setup_customer_usage_groups(customers_data):
    """
    customers_data: List of dicts with customer info from your database
    Example: [{"name": "Acme Corp", "schema_prefix": "acme_", "budget": 2000}]
    """
    for customer in customers_data:
        filter_expr = {
            "operator": "or",
            "filters": [
                {
                    "field": "database_schema_name",
                    "operator": "like",
                    "values": [f"%{customer['schema_prefix']}%"]
                }
            ]
        }

        create_usage_group(
            name=f"Customer: {customer['name']}",
            filter_expression=filter_expr,
            budget=customer.get('budget'),
            order=customer.get('order', 999)
        )

# Get customer data from your systems
customers = get_customers_from_database()  # Your function
setup_customer_usage_groups(customers)

```

### **Example 2: Environment-Based Cost Tracking**

```python
environments = [
    {"name": "Production", "pattern": "%_prod_%", "budget": 10000, "order": 1},
    {"name": "Staging", "pattern": "%_staging_%", "budget": 3000, "order": 2},
    {"name": "Development", "pattern": "%_dev_%", "budget": 2000, "order": 3}
]

for env in environments:
    filter_expr = {
        "operator": "or",
        "filters": [
            {
                "field": "warehouse_name",
                "operator": "like",
                "values": [env["pattern"]]
            }
        ]
    }

    create_usage_group(
        name=env["name"],
        filter_expression=filter_expr,
        budget=env["budget"],
        order=env["order"]
    )

```

## **Filter Discovery Tips**

### **🔍 Finding the Right Filter Dimensions**

1. **Start with the UI**: The interactive filter builder shows all available dimensions for your specific setup
2. **Use Terraform docs**: Browse real-world examples at [registry.terraform.io/providers/get-select/select](https://registry.terraform.io/providers/get-select/select/latest/docs)
3. **Check your data**: Look at your Snowflake `INFORMATION_SCHEMA` to understand your warehouse names, user patterns, etc.
4. **Test incrementally**: Start with simple filters and add complexity as needed

### **🎛️ Common Filter Patterns**

```python
# Pattern 1: Exact matches
{"field": "warehouse_name", "operator": "in", "values": ["WH1", "WH2"]}

# Pattern 2: Pattern matching
{"field": "user_name", "operator": "like", "values": ["analytics_%", "%_admin"]}

# Pattern 3: Tag-based filtering
{"field": "warehouse_tags", "operator": "array_contains", "values": ["team: analytics"]}

# Pattern 4: Multiple criteria (AND)
{
    "operator": "and",
    "filters": [
        {"field": "warehouse_name", "operator": "in", "values": ["PROD_WH"]},
        {"field": "user_name", "operator": "like", "values": ["prod_%"]}
    ]
}

# Pattern 5: Multiple criteria (OR)
{
    "operator": "or",
    "filters": [
        {"field": "warehouse_name", "operator": "in", "values": ["DEV_WH"]},
        {"field": "warehouse_name", "operator": "in", "values": ["TEST_WH"]}
    ]
}

```

## **Best Practices**

1. **🎯 Start Simple**: Begin with basic warehouse or user-based filters before adding complexity
2. **🧪 Test in UI First**: Always prototype your filters in the SELECT interface before coding
3. **📖 Use Terraform Docs**: Reference our provider docs for proven filter patterns
4. **🔄 Handle Existing Data**: Check for existing usage groups to avoid duplicates
5. **📊 Monitor Results**: Use the SELECT dashboard to verify your usage groups are working as expected
6. **⚡ Order Matters**: Lower order values take precedence when filter expressions overlap

## **Troubleshooting**

**❌ "Filter expression validation failed"**

- Copy a working filter from the UI and modify it incrementally
- Check that field names match available dimensions for your scope (account vs organization)

**❌ "Usage group name already exists"**

- Use the "get existing usage groups" pattern above to check before creating

**❌ "API key doesn't have access"**

- Verify your API key has `usage_groups:write` scope
- Ensure the key has access to the specific Snowflake account/organization
- Organization access grants access to all accounts as well

For more complex scenarios, consider using our [Terraform provider](https://registry.terraform.io/providers/get-select/select/latest/docs) which provides a more robust way to manage usage groups as infrastructure-as-code.
