Metadata-Version: 2.1
Name: feature_billing_iapi
Version: 3.2.0
Summary: IAPI Interface Files
Home-page: https://github.com/Cloudzero/cloudzero-feature-billing
Author: CloudZero
Author-email: support@cloudzero.com
License: UNLICENSED
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Description-Content-Type: text/markdown
Requires-Dist: cz-common-python>=4.0.0
Requires-Dist: attrdict>=2.0.0
Requires-Dist: feature_dimensions_iapi>=1.1.0
Requires-Dist: feature_data_access_controls_iapi>=1.0.0


# Billing IAPI

This package contains the interface for the billing IAPI.

## Table of Contents

### Data API Functions
- [`get_billing_data`](#get_billing_data) - Retrieve aggregated billing data with flexible grouping and filtering
- [`get_data_projection`](#get_data_projection) - Get SQL for which can be used in a CTE for access to billing data
- [`get_member_available_partitions`](#get_member_available_partitions) - Get metadata about available partitions (dimensions)
- [`get_partition_values`](#get_partition_values) - Retrieve distinct values for a partition type
- [`get_active_telemetry_streams`](#get_active_telemetry_streams) - List active telemetry streams
- [`get_available_dimensions`](#get_available_dimensions) - Get detailed dimension information with FQDIDs

### Cost Context Functions
- [`get_used_partition_types`](#get_used_partition_types) - List partition types used in cost contexts
- [`update_cost_context_definitions`](#update_cost_context_definitions) - Create or update custom cost contexts
- [`get_member_cost_view_for_instructions`](#get_member_cost_view_for_instructions) - Test cost context instructions without persisting

### Interface View Functions
- [`update_interface_view_definitions`](#update_interface_view_definitions) - Create Snowflake views into billing data

### Billing Ingest Functions
- [`new_billing_drop`](#new_billing_drop) - Trigger billing data ingestion

## Common Parameters

Many functions share common parameters. Here are their descriptions:

- **organization_id** (`str`): The unique identifier for the CloudZero organization. This is a UUID that identifies which organization's data to access.
- **granularity** (`GranularityType`): The time granularity for aggregating cost data. Options include:
  - `GranularityType.hourly`: Hourly aggregation
  - `GranularityType.daily`: Daily aggregation (default for most functions)
  - `GranularityType.monthly`: Monthly aggregation
- **date_range** (`DateRange`): A named tuple specifying the time period for the query:
  - `start` (`datetime`): The inclusive start date/time
  - `end` (`datetime`): The exclusive end date/time
- **filters** (`Dict[PartitionType, List[str]]`): A dictionary mapping partition types to lists of values to filter by. Only costs matching ALL filter criteria are included in results.
- **cost_type** (`CostType`): The type of cost to retrieve (real, amortized, or net amortized). Defaults to real cost.
- **authorization_context** (`Optional[AuthorizationContext]`): Context for data access controls and row-level security. If provided, results will be filtered based on the user's permissions.

## Data API Functions

### get_billing_data
Retrieves aggregated billing data for an organization within a specified date range. This is the primary API for fetching cost data, supporting flexible grouping by partitions (dimensions), time-based aggregation at various granularities, and filtering. The API returns cost data that can be broken down by any available partition type such as AWS service, region, account, or custom dimensions defined through cost contexts.

**Function Prototype:**
```python
def get_billing_data(
    *,
    organization_id: str,
    date_range: DateRange,
    granularity: GranularityType = GranularityType.daily,
    partitions: List[PartitionType] = None,
    filters: Dict[PartitionType, List[str]] = None,
    cost_type: CostType = CostType.real_cost,
    authorization_context: Optional[AuthorizationContext] = None,
)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **date_range**: [See common](#common-parameters)
- **granularity**: [See common](#common-parameters)
- **partitions** (`List[PartitionType]`): List of partition types to group the results by. If None, returns total costs without grouping.
- **filters**: [See common](#common-parameters)
- **cost_type**: [See common](#common-parameters)
- **authorization_context**: [See common](#common-parameters)

**Examples:**
```python
# Get daily AWS service costs for last week
result = get_billing_data(
    organization_id="123-456",
    date_range=DateRange(
        start=datetime(2024, 1, 1),
        end=datetime(2024, 1, 8)
    ),
    partitions=[PartitionType.service],
    granularity=GranularityType.daily
)

# Example result:
{
    'billing_data': [
        {
            'usage_date': '2024-01-01T00:00:00+00:00',
            'service': 'AmazonEC2',
            'cost': 1247.83
        },
        {
            'usage_date': '2024-01-01T00:00:00+00:00',
            'service': 'AmazonS3',
            'cost': 523.41
        },
        # ... more entries for each service and day
    ],
    'missing_time_periods': []
}

# Get hourly EC2 costs with filters
result = get_billing_data(
    organization_id="123-456",
    date_range=DateRange(start=datetime(2024, 1, 1), end=datetime(2024, 1, 2)),
    partitions=[PartitionType.service, PartitionType.region],
    filters={PartitionType.service: ["Amazon Elastic Compute Cloud"]},
    granularity=GranularityType.hourly
)

# Example result:
{
    'billing_data': [
        {
            'usage_date': '2024-01-01T00:00:00+00:00',
            'service': 'Amazon Elastic Compute Cloud',
            'region': 'us-east-1',
            'cost': 52.17
        },
        {
            'usage_date': '2024-01-01T00:00:00+00:00',
            'service': 'Amazon Elastic Compute Cloud',
            'region': 'us-west-2',
            'cost': 31.92
        },
        # ... more entries for each hour and region
    ],
    'missing_time_periods': []
}
```

### get_data_projection
Returns a queryable SQL CTE expression that, if one were to select * from it, would return the same data as get_billing_data above with all CostTypes available. Here, dimensions is a mapping of column names to be provided by that CTE to partitions as above. Note that all CTE elements will be prefixed with _ – avoid manually using such a prefix in your queries in order to avoid collisions.

Note also: the returned metadata should be passed to cz_snowflake for tracking. Optionally, you can replace its query_type with something more specific.

**Function Prototype:**
```python
def get_data_projection(
    *,
    organization_id: str,
    date_range: DateRange,
    dimensions: Dict[str, PartitionType],
    granularity: GranularityType = GranularityType.daily,
    filters: Dict[PartitionType, List[str]] = None,
    authorization_context: Optional[AuthorizationContext] = None,
    data_access_column: Optional[str] = None,
)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **date_range**: [See common](#common-parameters)
- **dimensions** (`Dict[str, PartitionType]`): A dictionary mapping dimension names to partition types. Each dimension will create a column in the projection.
- **granularity**: [See common](#common-parameters)
- **filters**: [See common](#common-parameters)
- **authorization_context**: [See common](#common-parameters)
- **data_access_column** (`str`): Optional column name for data access control information. When specified, each row will include a column with data access permissions.

**Examples:**
```python
# Project costs by custom team dimension
result = get_data_projection(
    organization_id="123-456",
    date_range=DateRange(start=datetime(2024, 1, 1), end=datetime(2024, 1, 31)),
    dimensions={"team": PartitionType.custom("team")},
    granularity=GranularityType.daily,
    data_access_column="access_permissions"
)

# Example result:
{
    'expression': '_projection_abc123 AS (SELECT ...',  # SQL CTE expression
    'name': '_projection_abc123',                       # Table name to query
    'metadata': {
        'query_type': 'data_projection',
        'organization_id': '123-456',
        'dimensions': {'team': 'costcontext:team'},
        'granularity': 'daily',
        'date_range': {
            'start': '2024-01-01T00:00:00+00:00',
            'end': '2024-01-31T00:00:00+00:00'
        }
    }
}

# When querying this projection the result will be something like:
# {
#     'usage_date': '2024-01-01T00:00:00+00:00',
#     'team': 'platform',
#     'service': 'AmazonEC2',
#     'real_cost': 1234.56,
#     <other cost types...>,
#     'access_permissions': {
#         'CZ:DataAccess:fdac_081772e1_7554_4c1a_8c16_50b644ced312': 'Allow',
#         'CZ:DataAccess:fdac_123456e7_8901_4cba_9876_54b321ced098': 'Allow',
#     }
# }
```

### get_member_available_partitions
Returns comprehensive metadata about all available partitions (dimensions) that can be used for cost analysis within an organization. This includes both standard AWS partitions (like service, region, account) and custom dimensions created through cost contexts.

**Function Prototype:**
```python
def get_member_available_partitions(*, organization_id: str, include_hidden: bool = False)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **include_hidden** (`bool`): Whether to include hidden partitions in the results. Defaults to False.

**Examples:**
```python
# Get all visible partitions
result = get_member_available_partitions(organization_id="123-456")

# Example result:
{
    'partition_types': {
        'static': ['service', 'account', 'region', 'availability_zone', 'instance_type'],
        'tag': ['Environment', 'Team', 'Application', 'Owner'],
        'costcontext': ['Product', 'Department', 'Project'],
        'k8slabel': ['app', 'version', 'namespace']
    },
    'pending_partition_types': {
        'static': [],
        'tag': ['NewTag'],
        'costcontext': [],
        'k8slabel': []
    },
    'last_complete_granularity_unit': {
        'hourly': '2024-01-15T23:00:00+00:00',
        'daily': '2024-01-14T00:00:00+00:00',
        'monthly': '2024-01-01T00:00:00+00:00'
    },
    'usage_date_bounds': {
        'first_usage_date': '2023-01-01T00:00:00+00:00',
        'last_usage_date': '2024-01-15T23:00:00+00:00'
    },
    'local_currency': 'USD',
    'cost_types': [
        'real_cost',
        # ... other cost types
    ],
    'cost_type_details': {
        'real_cost': {
            'display_name': 'Real Cost',
            'explorer_visibility': 'show',
            'analytics_visibility': 'hide'
        },
        # ... other cost types
    }
}

# Include hidden partitions
all_partitions = get_member_available_partitions(
    organization_id="123-456",
    include_hidden=True
)
```

### get_partition_values
Retrieves all distinct values present in the billing data for a specified partition type. This API is essential for building filter dropdowns, validating partition values, and understanding the cardinality of dimensions. It supports pattern matching for typeahead functionality, date range filtering to get values for specific time periods, and result limiting for performance optimization. The API intelligently queries the appropriate data sources based on the partition type and time range, ensuring efficient retrieval even for high-cardinality dimensions like resource IDs or tags.

**Function Prototype:**
```python
def get_partition_values(
    *,
    organization_id: str,
    partition: PartitionType,
    date_range: DateRange = None,
    granularity: GranularityType = GranularityType.daily,
    match: str = None,
    limit: int = None,
)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **partition** (`PartitionType`): The partition type to retrieve values for.
- **date_range**: [See common](#common-parameters)
- **granularity**: [See common](#common-parameters)
- **match** (`str`): Optional pattern to filter values (supports SQL LIKE wildcards).
- **limit** (`int`): Maximum number of values to return.

**Examples:**
```python
# Get all AWS services used
result = get_partition_values(
    organization_id="123-456",
    partition=PartitionType.service
)

# Example result:
{
    'values': [
        'AmazonEC2',
        'AmazonS3',
        'AWSLambda',
        'AmazonRDS',
        'AmazonCloudWatch',
        'AmazonDynamoDB',
        # ... more services
    ],
    'total_count': 47
}

# Get regions matching "us-" pattern
result = get_partition_values(
    organization_id="123-456",
    partition=PartitionType.region,
    match="us-",
    limit=10
)

# Example result:
{
    'values': [
        'us-east-1',
        'us-east-2',
        'us-west-1',
        'us-west-2'
    ],
    'total_count': 4
}
```

### get_active_telemetry_streams
Returns a list of active telemetry streams configured for cost allocation.

**Function Prototype:**
```python
def get_active_telemetry_streams(*, organization_id: str)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)

**Examples:**
```python
result = get_active_telemetry_streams(organization_id="123-456")

# Example result:
{
    'streams': [
        {
            'stream_id': 'telemetry-api-requests',
            'name': 'API Gateway Request Count',
            'dimensions': ['service', 'region', 'api_name'],
            'status': 'active',
            'created_at': '2023-06-15T10:30:00+00:00'
        },
        {
            'stream_id': 'telemetry-lambda-invocations',
            'name': 'Lambda Invocation Count',
            'dimensions': ['function_name', 'region'],
            'status': 'active',
            'created_at': '2023-07-01T14:20:00+00:00'
        }
    ]
}
```

### get_available_dimensions
Returns detailed information about all available dimensions including their FQDIDs, aliases, and display names.

**Function Prototype:**
```python
def get_available_dimensions(*, organization_id: str, include_hidden: bool = False) -> AvailableDimensions
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **include_hidden** (`bool`): Whether to include hidden dimensions in the results. Defaults to False.

**Returns:**
- **AvailableDimensions**: Object containing a list of available dimensions with their metadata.

**Examples:**
```python
# Get visible dimensions
result = get_available_dimensions(organization_id="123-456")

# Example result (AvailableDimensions object):
AvailableDimensions(
    dimensions=[
        AvailableDimension(
            fqdid='CZ:Service',
            aliases=['service', 'services'],
            display_name='Service',
            hidden=False
        ),
        AvailableDimension(
            fqdid='CZ:Region',
            aliases=['region', 'regions'],
            display_name='Region',
            hidden=False
        ),
        AvailableDimension(
            fqdid='CZ:Account',
            aliases=['account', 'accounts'],
            display_name='Account',
            hidden=False
        ),
        AvailableDimension(
            fqdid='CZ:CostContext:Team',
            aliases=['team'],
            display_name='Team',
            hidden=False
        ),
        # ... more dimensions
    ]
)

# Include hidden dimensions
all_dimensions = get_available_dimensions(
    organization_id="123-456",
    include_hidden=True
)
```

## Cost Context Functions

### get_used_partition_types
Returns a list of partition types that are referenced in the organization's cost context definitions.

**Function Prototype:**
```python
def get_used_partition_types(*, organization_id: str) -> List[PartitionType]
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)

**Returns:**
- **List[PartitionType]**: List of partition types referenced in cost context definitions.

**Examples:**
```python
result = get_used_partition_types(organization_id="123-456")

# Example result (List[PartitionType]):
[
    PartitionType('service'),
    PartitionType('account'),
    PartitionType('region'),
    PartitionType('tag:Environment'),
    PartitionType('tag:Team'),
    PartitionType('costcontext:Product'),
    PartitionType('costcontext:Department')
]
```

### update_cost_context_definitions
Creates or updates custom cost contexts (dimensions) including group contexts, telemetry contexts, and allocation rules.

**Function Prototype:**
```python
def update_cost_context_definitions(
    *,
    organization_id: str,
    instructions: Union[List[GroupContextDefinition], Instructions, PresignedURL],
    delay_materialization: bool = False
)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **instructions** (`Union[List[GroupContextDefinition], Instructions, PresignedURL]`): The cost context definitions to create or update. Can be:
  - A list of GroupContextDefinition objects
  - An Instructions object containing group, telemetry, and allocation rules
  - A PresignedURL for large payloads
- **delay_materialization** (`bool`): If True, delays the materialization of the cost contexts. Useful for bulk updates. Defaults to False.

**Examples:**
```python
# Update with group context definitions
update_cost_context_definitions(
    organization_id="123-456",
    instructions=[
        GroupContextDefinition(
            name="Team",
            hidden=False,
            references={},
            value={"type": "partition", "value": "tag:Team"},
            aliases=["team", "Team"]
        )
    ]
)

# Note: This function updates definitions and typically returns empty on success
# or raises an exception on failure

# Update with full instructions including allocations
update_cost_context_definitions(
    organization_id="123-456",
    instructions=Instructions(
        group=[...],
        telemetry=[...],
        allocation_rules=[...]
    ),
    delay_materialization=True
)
```

### get_member_cost_view_for_instructions
Evaluates cost context instructions on-the-fly without persisting them, useful for testing dimension definitions.

**Function Prototype:**
```python
def get_member_cost_view_for_instructions(
    *,
    organization_id: str,
    instructions: List[dict],
    partition_by: PartitionType,
    granularity: GranularityType,
    start_date: datetime,
    end_date: datetime,
    filters: Dict[PartitionType, List[str]] = None,
    cost_type: CostType = None,
    max_partitions: int = None,
    partition_sort_type: PartitionSortType = None,
    partition_sort_direction: PartitionSortDirection = None,
    allow_allocation_dimensions: bool = False,
)
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **instructions** (`List[dict]`): List of cost context instruction dictionaries to evaluate.
- **partition_by** (`PartitionType`): The partition type to group results by.
- **granularity**: [See common](#common-parameters)
- **start_date** (`datetime`): The inclusive start date for the cost view.
- **end_date** (`datetime`): The exclusive end date for the cost view.
- **filters**: [See common](#common-parameters)
- **cost_type**: [See common](#common-parameters)
- **max_partitions** (`int`): Maximum number of partition values to return.
- **partition_sort_type** (`PartitionSortType`): How to sort the partition results (by cost, alphabetically, etc.).
- **partition_sort_direction** (`PartitionSortDirection`): Sort direction (ascending or descending).
- **allow_allocation_dimensions** (`bool`): Whether to allow allocation dimensions in the results. Defaults to False.

**Examples:**
```python
# Test a new dimension definition
result = get_member_cost_view_for_instructions(
    organization_id="123-456",
    instructions=[{
        "name": "Environment",
        "type": "group",
        "value": {"type": "partition", "value": "tag:Environment"}
    }],
    partition_by=PartitionType.custom("Environment"),
    granularity=GranularityType.daily,
    start_date=datetime(2024, 1, 1),
    end_date=datetime(2024, 1, 31)
)

# Example result:
{
    'cost_totals': {'real_cost': 45632.18},
    'cost_type': 'real_cost',
    'end_date': '2024-01-31T23:59:59+00:00',
    'filters': {},
    'granularity': 'daily',
    'partition_by': 'costcontext:Environment',
    'start_date': '2024-01-01T00:00:00+00:00',
    'partitions': ['production', 'staging', 'development', 'qa'],
    'sorted_by': 'real_cost',
    'has_complete_prior_period': True,
    'trend_totals': {
        'real_cost': {
            'cost': 45632.18,
            'prior_cost': 43521.67,
            'magnitude': 2110.51,
            'percent_change': 0.0485
        }
    },
    'partition_costs': [
        {
            'partition': 'production',
            'cost': 28914.52,
            'cost_per_day': 932.73,
            'percentage': 0.6336
        },
        {
            'partition': 'staging',
            'cost': 9231.44,
            'cost_per_day': 297.79,
            'percentage': 0.2023
        },
        {
            'partition': 'development',
            'cost': 5782.91,
            'cost_per_day': 186.55,
            'percentage': 0.1267
        },
        {
            'partition': 'qa',
            'cost': 1703.31,
            'cost_per_day': 54.95,
            'percentage': 0.0373
        }
    ],
    'partition_trends': [
        {
            'partition': 'production',
            'trend': {
                'cost': 28914.52,
                'prior_cost': 27102.33,
                'magnitude': 1812.19,
                'percent_change': 0.0669
            }
        },
        # ... trends for other partitions
    ]
}
```

## Interface View Functions

### update_interface_view_definitions
Creates or updates interface views which are pre-aggregated views optimized for specific UI components.

**Function Prototype:**
```python
def update_interface_view_definitions(organization_id: str, definitions: List[InterfaceViewDefinition])
```

**Parameters:**
- **organization_id**: [See common](#common-parameters)
- **definitions** (`List[InterfaceViewDefinition]`): List of interface view definitions to create or update. Each definition specifies:
  - `name`: Unique name for the view
  - `dimensions`: Dictionary mapping dimension names to partition types
  - `granularity`: Time granularity for the view
  - `timespan`: Optional time range to include in the view
  - `filters`: Optional filters to apply to the view

**Examples:**
```python
# Create a view for service costs by day
update_interface_view_definitions(
    organization_id="123-456",
    definitions=[
        InterfaceViewDefinition(
            name="service_daily_costs",
            dimensions={"service": "service"},
            granularity=GranularityType.daily,
            timespan=InterfaceViewTimespan(unit=TimespanUnit.days, value=30)
        )
    ]
)

# Note: This function creates/updates view definitions and typically returns empty on success
# The views can then be queried using other APIs

# Create a filtered view for production environment
update_interface_view_definitions(
    organization_id="123-456",
    definitions=[
        InterfaceViewDefinition(
            name="production_costs",
            dimensions={"service": "service", "region": "region"},
            granularity=GranularityType.daily,
            filters={"environment": ["production"]},
            timespan=InterfaceViewTimespan(unit=TimespanUnit.weeks, value=4)
        )
    ]
)
```

## Billing Ingest Functions

### new_billing_drop
Initiates the billing data ingestion process for specified billing periods.

**Function Prototype:**
```python
def new_billing_drop(
    *,
    connection_id: str,
    organization_id: str,
    billing_periods: List[str],
    use_rate_limiting: bool = False
)
```

**Parameters:**
- **connection_id** (`str`): The billing connection identifier (e.g., AWS account ID).
- **organization_id**: [See common](#common-parameters)
- **billing_periods** (`List[str]`): List of billing periods to ingest in YYYYMMDD-YYYYMMDD format.
- **use_rate_limiting** (`bool`): Whether to apply rate limiting during ingestion. Defaults to False.

**Examples:**
```python
# Trigger ingestion for multiple billing periods
result = new_billing_drop(
    connection_id="aws-123456789012",
    organization_id="123-456",
    billing_periods=["20240101-20240201", "20240201-20240301"],
    use_rate_limiting=True
)

# Example result:
{
    'status': 'started',
    'job_id': 'ingest-abc123def456',
    'connection_id': 'aws-123456789012',
    'organization_id': '123-456',
    'billing_periods': ['20240101-20240201', '20240201-20240301'],
    'message': 'Billing data ingestion initiated successfully'
}
```

## Deprecated Functions

The following functions are deprecated and should no longer be used:
- `get_total_cost_per_hour`
