Claude
Skills
Sign in
Back

policyengine-python-client

Included with Lifetime
$97 forever

ONLY use this skill when users explicitly ask about the PolicyEngine Python package installation, REST API endpoints, API authentication, rate limits, or policyengine.py client library. DO NOT use for household benefit/tax calculations — ALWAYS use policyengine-us or policyengine-uk instead. This skill is about the API/client tooling itself, not about calculating benefits or taxes.

Backend & APIs

What this skill does


# PolicyEngine Python Client

> **IMPORTANT: Always use the current year (2026) in situation dictionaries and calculate() calls, not 2024 or 2025.**

This skill covers programmatic access to PolicyEngine for analysts and researchers.

## Installation

If the user asks for the latest PolicyEngine package version, verify from PyPI
immediately before installing. Do not rely on search snippets, local installed
packages, lockfiles, or old docs as proof of latest.

```bash
# Verify the latest umbrella package on PyPI.
python - <<'PY'
import json
import urllib.request

with urllib.request.urlopen(
    "https://pypi.org/pypi/policyengine/json",
    timeout=20,
) as response:
    print(json.load(response)["info"]["version"])
PY
python -m pip index versions policyengine

# Install the Python client, pinned to the verified version.
uv pip install "policyengine==X.Y.Z"

# Or for local development
uv pip install policyengine-us  # Just the US model (offline)
```

When using `policyengine.py` as the source of both rules and default microdata,
install the country extra at the exact verified umbrella package version:

```bash
uv pip install "policyengine[us]==X.Y.Z"
uv pip install "policyengine[uk]==X.Y.Z"
```

If the user instead asks for the latest direct country package, run the same
PyPI JSON + `pip index` check for `policyengine-us`, `policyengine-uk`, or the
specific package named by the user, then pin that exact package version.

Confirm the resolved package versions and whether any package is a direct GitHub
install:

```bash
python - <<'PY'
from importlib import metadata

for package in ["policyengine", "policyengine-us", "policyengine-uk"]:
    try:
        print(f"{package}=={metadata.version(package)}")
        direct_url = metadata.distribution(package).read_text("direct_url.json")
        if direct_url:
            print(f"{package} direct_url={direct_url}")
    except metadata.PackageNotFoundError:
        pass
PY
```

For bundle/data provenance, inspect the installed release manifest directly
instead of relying on a top-level `import policyengine`; top-level imports can
initialize countries you are not using and may require private data tokens.

```bash
python - <<'PY'
import json
from importlib import metadata
from pathlib import Path

country = "us"
manifest_path = Path(
    metadata.distribution("policyengine").locate_file(
        f"policyengine/data/release_manifests/{country}.json"
    )
)
manifest = json.loads(manifest_path.read_text())
print(json.dumps({
    "bundle_id": manifest.get("bundle_id"),
    "model_package": manifest.get("model_package"),
    "data_package": manifest.get("data_package"),
    "default_dataset": manifest.get("default_dataset"),
    "default_dataset_uri": (
        manifest.get("certified_data_artifact") or {}
    ).get("uri"),
    "certification": manifest.get("certification"),
}, indent=2, sort_keys=True))
PY
```

## Quick Start: Python Client

```python
from policyengine import Simulation

# Create a household
household = {
    "people": {
        "you": {
            "age": {"2026": 30},
            "employment_income": {"2026": 50000}
        }
    },
    "households": {
        "your household": {
            "members": ["you"],
            "state_name": {"2026": "CA"}
        }
    }
}

# Run simulation
sim = Simulation(situation=household, country_id="us")
income_tax = sim.calculate("income_tax", "2026")
```

## For Users: Why Use Python?

**Web app limitations:**
- ✅ Great for exploring policies interactively
- ❌ Can't analyze many households at once
- ❌ Can't automate repetitive analyses
- ❌ Limited customization of charts

**Python benefits:**
- ✅ Analyze thousands of households in batch
- ✅ Automate regular policy analysis
- ✅ Create custom visualizations
- ✅ Integrate with other data sources
- ✅ Reproducible research

## For Analysts: Common Workflows

### Workflow 1: Calculate Your Own Taxes

```python
from policyengine import Simulation

# Your household (more complex than web app)
household = {
    "people": {
        "you": {
            "age": {"2026": 35},
            "employment_income": {"2026": 75000},
            "qualified_dividend_income": {"2026": 5000},
            "charitable_cash_donations": {"2026": 3000}
        },
        "spouse": {
            "age": {"2026": 33},
            "employment_income": {"2026": 60000}
        },
        "child1": {"age": {"2026": 8}},
        "child2": {"age": {"2026": 5}}
    },
    # ... entities setup (see policyengine-us-skill)
}

sim = Simulation(situation=household, country_id="us")

# Calculate specific values
federal_income_tax = sim.calculate("income_tax", "2026")
state_income_tax = sim.calculate("state_income_tax", "2026")
ctc = sim.calculate("ctc", "2026")
eitc = sim.calculate("eitc", "2026")

print(f"Federal income tax: ${federal_income_tax:,.0f}")
print(f"State income tax: ${state_income_tax:,.0f}")
print(f"Child Tax Credit: ${ctc:,.0f}")
print(f"EITC: ${eitc:,.0f}")
```

### Workflow 2: Analyze a Policy Reform

```python
from policyengine import Simulation

# Define reform (increase CTC to $5,000)
reform = {
    "gov.irs.credits.ctc.amount.base[0].amount": {
        "2026-01-01.2100-12-31": 5000
    }
}

# Compare baseline vs reform
household = create_household()  # Your household definition

sim_baseline = Simulation(situation=household, country_id="us")
sim_reform = Simulation(situation=household, country_id="us", reform=reform)

ctc_baseline = sim_baseline.calculate("ctc", "2026")
ctc_reform = sim_reform.calculate("ctc", "2026")

print(f"CTC baseline: ${ctc_baseline:,.0f}")
print(f"CTC reform: ${ctc_reform:,.0f}")
print(f"Increase: ${ctc_reform - ctc_baseline:,.0f}")
```

### Workflow 3: Batch Analysis

```python
import pandas as pd
from policyengine import Simulation

# Analyze multiple households
households = [
    {"income": 30000, "children": 0},
    {"income": 50000, "children": 2},
    {"income": 100000, "children": 3},
]

results = []
for h in households:
    situation = create_household(income=h["income"], num_children=h["children"])
    sim = Simulation(situation=situation, country_id="us")

    results.append({
        "income": h["income"],
        "children": h["children"],
        "income_tax": sim.calculate("income_tax", "2026"),
        "ctc": sim.calculate("ctc", "2026"),
        "eitc": sim.calculate("eitc", "2026")
    })

df = pd.DataFrame(results)
print(df)
```

## Using the REST API Directly

### Authentication

**Public access:**
- 100 requests per minute (unauthenticated)
- No API key needed for basic use

**Authenticated access:**
- 1,000 requests per minute
- Contact [email protected] for API key

### Key Endpoints

**Calculate household impact:**
```python
import requests

url = "https://api.policyengine.org/us/calculate"
payload = {
    "household": household_dict,
    "policy_id": reform_id  # or None for baseline
}

response = requests.post(url, json=payload)
result = response.json()
```

**Get policy details:**
```python
# Get policy metadata
response = requests.get("https://api.policyengine.org/us/policy/12345")
policy = response.json()
```

**Get parameter values:**
```python
# Get current parameter value
response = requests.get(
    "https://api.policyengine.org/us/parameter/gov.irs.credits.ctc.amount.base"
)
parameter = response.json()
```

### For Full API Documentation

**OpenAPI spec:** https://api.policyengine.org/docs

**To explore:**
```bash
# View all endpoints
curl https://api.policyengine.org/docs

# Test calculate endpoint
curl -X POST https://api.policyengine.org/us/calculate \
  -H "Content-Type: application/json" \
  -d '{"household": {...}}'
```

## Limitations and Considerations

### Rate Limits

**Unauthenticated:**
- 100 requests/minute
- Good for exploratory analysis

**Authenticated:**
- 1,000 requests/minute
- Required for production use

### Data Privacy

- PolicyEngine does not store household data
- All calculations happen server-side and are not logged
- Reform URLs are public

Related in Backend & APIs