# Retrieving Variable Rate Values from Arcadia APIs

> ⚠️ **Disclaimer**: This guide was generated by an LLM (Claude Opus 4.5) based on Arcadia API documentation and the model's understanding of the API structure. The content looks reasonable but **has not been verified by domain experts**. Please verify any claims and test API calls before relying on them for production use.

---

## You Have a Tariff—Now What?

You downloaded a tariff (like ConEd EL1) and see rates with `variableRateKey`:

```json
{
  "rateName": "MSC Rate - Zone J",
  "rateAmount": 0.0,
  "variableRateKey": "marketSupplyChargeResidentialZoneJ"
}
```

The `rateAmount: 0.0` is a placeholder. The actual values change over time (monthly, in most cases). To get them, you have two options:

| Approach          | How It Works                                                       | What You Get                                    |
| ----------------- | ------------------------------------------------------------------ | ----------------------------------------------- |
| **Lookups API**   | Extract `variableRateKey` values from tariff → query each one      | Raw rate values, exactly what you asked for     |
| **Calculate API** | Use tariff metadata to set up a billing scenario → run calculation | All applicable rates resolved for that scenario |

**Key difference**: These approaches don't always give the same results.

---

## ⚠️ Important: The Two Approaches Are Not Equivalent

### Lookups API = Raw Data, You Control What You Query

- You explicitly request specific `variableRateKey` values
- You get exactly those values, regardless of whether they apply to a specific customer
- Zone H, Zone I, Zone J rates? You can query all of them
- Solar-only rates? You get them even if you're not modeling a solar customer

### Calculate API = Scenario-Based, API Filters for Applicability

- You specify a billing scenario: territory, consumption, solar system size, etc.
- The API returns **only rates that apply to that scenario**
- Zone J customer? You only get Zone J rates
- No solar (`systemSize: 0`)? You won't get the CBC charge

### When Results Match

If you:

1. Query Lookups for only the `variableRateKey` values that apply to your scenario
2. Use Calculate with the same scenario parameters

...you'll get the same variable rate values.

### When Results Differ

| Scenario                          | Lookups API                      | Calculate API                       |
| --------------------------------- | -------------------------------- | ----------------------------------- |
| Query all zone-specific MSC rates | Returns H, I, and J values       | Returns only the zone you specified |
| Customer without solar            | Returns CBC rate if you query it | Won't include CBC (doesn't apply)   |
| Query a key that doesn't apply    | Returns data anyway              | Won't appear in results             |

**Bottom line**: Lookups gives you raw data; Calculate gives you scenario-specific data.

---

## Workflow: From Tariff to Variable Rates

### Method 1: Lookups API

**Step 1: Extract all `variableRateKey` values from the tariff**

Parse the tariff JSON and collect every unique `variableRateKey`:

```python
import json

def extract_variable_rate_keys(tariff_json):
    """Extract all variableRateKey values from a tariff."""
    keys = set()

    for tariff in tariff_json:
        for rate in tariff.get('rates', []):
            if 'variableRateKey' in rate:
                keys.add(rate['variableRateKey'])

    return list(keys)

# Load your tariff
with open('coned_el1_tariff.json') as f:
    tariff = json.load(f)

variable_keys = extract_variable_rate_keys(tariff)
print(f"Found {len(variable_keys)} variable rate keys")
```

**For ConEd EL1, this returns keys like:**

```python
[
    "marketSupplyChargeResidentialZoneH",
    "marketSupplyChargeResidentialZoneI",
    "marketSupplyChargeResidentialZoneJ",
    "mscIResidentialWestchester2252",
    "mscIResidentialNewYork2252",
    "mscIIAdjustmentFactor",
    "monthlyAdjustmentClauseResidential",
    # ... 15+ more
]
```

**Step 2: Query Lookups API for each key**

```python
import requests

def get_lookups(property_key, from_date, to_date, api_key):
    """Get lookup values for a single variableRateKey."""
    response = requests.get(
        f"https://api.arcadia.com/rest/public/properties/{property_key}/lookups",
        params={
            "fromDateTime": from_date,
            "toDateTime": to_date
        },
        headers={"Authorization": f"Bearer {api_key}"}
    )
    return response.json().get('results', [])

# Get 2024 data for all keys
all_lookups = {}
for key in variable_keys:
    all_lookups[key] = get_lookups(
        key,
        "2024-01-01T00:00:00-05:00",
        "2025-01-01T00:00:00-05:00",
        "YOUR_API_KEY"
    )

print(f"Retrieved data for {len(all_lookups)} variable rates")
```

**Step 3: Organize by time period**

```python
def organize_by_month(all_lookups):
    """Reorganize lookup data by month."""
    monthly = {}

    for key, entries in all_lookups.items():
        for entry in entries:
            # Extract month from fromDateTime
            month = entry['fromDateTime'][:7]  # "2024-01"

            if month not in monthly:
                monthly[month] = {}

            monthly[month][key] = entry['bestValue']

    return monthly

monthly_rates = organize_by_month(all_lookups)

# Result:
# {
#   "2024-01": {"marketSupplyChargeResidentialZoneJ": 0.0823, ...},
#   "2024-02": {"marketSupplyChargeResidentialZoneJ": 0.0791, ...},
#   ...
# }
```

**Calls required**: One per `variableRateKey` (typically 15-20 for ConEd EL1)

---

### Method 2: Calculate API

**Step 1: Extract scenario parameters from the tariff**

The tariff tells you what parameters the Calculate API needs:

```python
def get_calculate_params(tariff_json):
    """Extract parameters needed for Calculate API from tariff."""
    tariff = tariff_json[0]  # First tariff in array

    return {
        "masterTariffId": tariff['masterTariffId'],
        "lseId": tariff['lseId'],
        # Get available territories from properties
        "territories": [
            choice['value']
            for prop in tariff.get('properties', [])
            if prop['keyName'] == 'territoryId'
            for choice in prop.get('choices', [])
        ]
    }

params = get_calculate_params(tariff)
# Result:
# {
#   "masterTariffId": 809,
#   "lseId": 2252,
#   "territories": ["3632", "3633", "3634"]  # H, I, J
# }
```

**Step 2: Call Calculate API for each billing period**

```python
def calculate_bill(master_tariff_id, territory_id, from_date, to_date, consumption, api_key):
    """Run a bill calculation and return line items."""
    response = requests.post(
        "https://api.arcadia.com/rest/public/calculate",
        json={
            "masterTariffId": master_tariff_id,
            "fromDateTime": from_date,
            "toDateTime": to_date,
            "territoryId": int(territory_id),
            "detailLevel": "CHARGE_TYPE_AND_TOU",
            "propertyInputs": [
                {"keyName": "consumption", "dataValue": consumption}
            ]
        },
        headers={"Authorization": f"Bearer {api_key}"}
    )
    return response.json()

# Get 2024 data for Zone J
monthly_results = {}
for month in range(1, 13):
    from_date = f"2024-{month:02d}-01"
    to_date = f"2024-{month+1:02d}-01" if month < 12 else "2025-01-01"

    result = calculate_bill(
        master_tariff_id=809,
        territory_id=3634,  # Zone J
        from_date=from_date,
        to_date=to_date,
        consumption=500,  # Arbitrary—we just want rate values
        api_key="YOUR_API_KEY"
    )
    monthly_results[f"2024-{month:02d}"] = result
```

**Step 3: Extract rate values from responses**

```python
def extract_rate_values(calculate_response):
    """Extract rate values from Calculate API response."""
    rates = {}

    for item in calculate_response['results'][0]['items']:
        rate_name = item['tariffRateName']
        rate_amount = item['rateAmount']
        rates[rate_name] = rate_amount

    return rates

monthly_rates = {
    month: extract_rate_values(result)
    for month, result in monthly_results.items()
}

# Result:
# {
#   "2024-01": {"Customer Charge": 20.0, "MSC Rate - Zone J": 0.0823, ...},
#   "2024-02": {"Customer Charge": 20.0, "MSC Rate - Zone J": 0.0791, ...},
#   ...
# }
```

**Calls required**: One per billing period (12 for a year of monthly data)

---

## Filtering Calculate API Results to Just Variable Rates

The Calculate API returns ALL charges (fixed and variable). To get just variable rates, cross-reference with the tariff:

```python
def filter_to_variable_rates(tariff_json, calculate_response):
    """Filter Calculate results to only variable rates."""

    # Build set of rate names that have variableRateKey
    variable_rate_names = set()
    for tariff in tariff_json:
        for rate in tariff.get('rates', []):
            if 'variableRateKey' in rate:
                variable_rate_names.add(rate['rateName'])

    # Filter calculate results
    all_rates = extract_rate_values(calculate_response)
    variable_only = {
        name: value
        for name, value in all_rates.items()
        if name in variable_rate_names
    }

    return variable_only
```

---

## Can Calculate API Give the Same Results as Lookups?

**Short answer**: Yes, but only if you're careful about scenario matching.

### To Get Equivalent Results:

1. **Match the territory**: If you queried `marketSupplyChargeResidentialZoneJ` via Lookups, use `territoryId: 3634` in Calculate

2. **Match applicability conditions**: Some rates only apply in certain scenarios:
   - CBC only appears if `systemSize > 0`
   - Supply charges only appear if customer uses ConEd supply (not ESCO)

3. **Cross-reference by rate name**: The Calculate API uses `tariffRateName` which matches the `rateName` in the tariff JSON

### What Calculate API Cannot Do:

- **Return rates for multiple zones in one call**: You must call once per territory
- **Return rates that don't apply to your scenario**: If you set `systemSize: 0`, you won't get CBC
- **Give you forecast vs. actual breakdown**: Lookups has `bestValue`, `actualValue`, `forecastValue`; Calculate just gives you the resolved value

### When to Use Each:

| Goal                                                       | Use           |
| ---------------------------------------------------------- | ------------- |
| Get all variable rates for a specific customer scenario    | Calculate API |
| Get one rate's full history with forecast/actual breakdown | Lookups API   |
| Discover what variable rates exist without knowing keys    | Calculate API |
| Get raw data regardless of applicability                   | Lookups API   |

---

## API Reference Summary

### Lookups API

**Endpoint**: `GET /rest/public/properties/{propertyKey}/lookups`

**Parameters**:

| Parameter      | Required    | Description                    |
| -------------- | ----------- | ------------------------------ |
| `propertyKey`  | Yes         | The `variableRateKey`          |
| `fromDateTime` | Recommended | Start of date range (ISO 8601) |
| `toDateTime`   | Recommended | End of date range (ISO 8601)   |

**Default date behavior**: Last 72 hours if not specified.

**Response fields**:

- `bestValue`: Use this (best available value)
- `actualValue`: Finalized value (may be null)
- `forecastValue`: Arcadia's forecast
- `lseForecastValue`: Utility's forecast

### Calculate API

**Endpoint**: `POST /rest/public/calculate`

**Key request fields**:

| Field            | Required | Description                                 |
| ---------------- | -------- | ------------------------------------------- |
| `masterTariffId` | Yes      | From tariff JSON                            |
| `fromDateTime`   | Yes      | Billing period start                        |
| `toDateTime`     | Yes      | Billing period end                          |
| `territoryId`    | Depends  | Required if tariff has multiple territories |
| `detailLevel`    | Yes      | Use `CHARGE_TYPE_AND_TOU` or `RATE`         |
| `propertyInputs` | Yes      | At minimum, consumption                     |

**Response structure**:

- `results[0].items[]`: Array of line items
- Each item has `tariffRateName`, `rateAmount`, `itemQuantity`, `cost`

### Lookup Stats API

**Endpoint**: `GET /rest/public/properties/{propertyKey}/stats`

**Returns**: Date range available, count, mean value, last updated date.

---

## Complete Example: 2024 Variable Rates, Both Methods

### Setup

```python
import json
import requests
from datetime import datetime

API_KEY = "YOUR_API_KEY"
TARIFF_FILE = "coned_el1_tariff.json"

with open(TARIFF_FILE) as f:
    tariff = json.load(f)
```

### Method 1: Lookups API

```python
# Extract variable rate keys
variable_keys = []
for t in tariff:
    for rate in t.get('rates', []):
        if 'variableRateKey' in rate:
            variable_keys.append({
                'key': rate['variableRateKey'],
                'name': rate['rateName']
            })

# Deduplicate
unique_keys = {k['key']: k['name'] for k in variable_keys}

# Query each key
lookups_results = {}
for key, name in unique_keys.items():
    response = requests.get(
        f"https://api.arcadia.com/rest/public/properties/{key}/lookups",
        params={
            "fromDateTime": "2024-01-01T00:00:00-05:00",
            "toDateTime": "2025-01-01T00:00:00-05:00"
        },
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    lookups_results[name] = response.json().get('results', [])

print(f"Lookups API: {len(unique_keys)} calls made")
```

### Method 2: Calculate API (Zone J)

```python
calculate_results = {}
for month in range(1, 13):
    from_date = f"2024-{month:02d}-01"
    to_date = f"2024-{month+1:02d}-01" if month < 12 else "2025-01-01"

    response = requests.post(
        "https://api.arcadia.com/rest/public/calculate",
        json={
            "masterTariffId": 809,
            "fromDateTime": from_date,
            "toDateTime": to_date,
            "territoryId": 3634,
            "detailLevel": "CHARGE_TYPE_AND_TOU",
            "propertyInputs": [
                {"keyName": "consumption", "dataValue": 500}
            ]
        },
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    calculate_results[f"2024-{month:02d}"] = response.json()

print(f"Calculate API: 12 calls made")
```

### Compare Results

```python
# Get January 2024 MSC Rate - Zone J from both methods

# From Lookups
for entry in lookups_results.get("MSC Rate - Zone J", []):
    if entry['fromDateTime'].startswith("2024-01"):
        print(f"Lookups API: {entry['bestValue']}")

# From Calculate
for item in calculate_results["2024-01"]['results'][0]['items']:
    if item['tariffRateName'] == "MSC Rate - Zone J":
        print(f"Calculate API: {item['rateAmount']}")

# These should match!
```

---

## Summary

| Aspect                            | Lookups API                          | Calculate API                                |
| --------------------------------- | ------------------------------------ | -------------------------------------------- |
| **Input needed**                  | `variableRateKey` from tariff        | `masterTariffId`, `territoryId`, consumption |
| **Output**                        | Raw rate values with forecast/actual | Resolved rates for specific scenario         |
| **Calls for 1 year, all rates**   | ~16 (one per key)                    | 12 (one per month)                           |
| **Includes non-applicable rates** | Yes (if you query them)              | No (filtered by scenario)                    |
| **Forecast vs. actual breakdown** | Yes                                  | No                                           |
| **Discovers rates for you**       | No (you must know keys)              | Yes (returns all applicable)                 |

**Use Lookups when**: You know exactly which rates you want and need raw historical data.

**Use Calculate when**: You want all applicable rates for a billing scenario without knowing the keys upfront.
