# Policyengine Python Client

> Using PolicyEngine programmatically via Python client or REST API

- Skill: `majiayu000/policyengine-python-client` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/policyengine-python-client`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/policyengine-python-client/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/policyengine-python-client

---


# PolicyEngine Python Client

This skill covers programmatic access to PolicyEngine for analysts and researchers.

## Installation

```bash
# Install the Python client
pip install policyengine

# Or for local development
pip install policyengine-us  # Just the US model (offline)
```

## Quick Start: Python Client

```python
from policyengine import Simulation

# Create a household
household = {
    "people": {
        "you": {
            "age": {"2024": 30},
            "employment_income": {"2024": 50000}
        }
    },
    "households": {
        "your household": {
            "members": ["you"],
            "state_name": {"2024": "CA"}
        }
    }
}

# Run simulation
sim = Simulation(situation=household, country_id="us")
income_tax = sim.calculate("income_tax", "2024")
```

## 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": {"2024": 35},
            "employment_income": {"2024": 75000},
            "qualified_dividend_income": {"2024": 5000},
            "charitable_cash_donations": {"2024": 3000}
        },
        "spouse": {
            "age": {"2024": 33},
            "employment_income": {"2024": 60000}
        },
        "child1": {"age": {"2024": 8}},
        "child2": {"age": {"2024": 5}}
    },
    # ... entities setup (see policyengine-us-skill)
}

sim = Simulation(situation=household, country_id="us")

# Calculate specific values
federal_income_tax = sim.calculate("income_tax", "2024")
state_income_tax = sim.calculate("state_income_tax", "2024")
ctc = sim.calculate("ctc", "2024")
eitc = sim.calculate("eitc", "2024")

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_amount": {
        "2024-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", "2024")
ctc_reform = sim_reform.calculate("ctc", "2024")

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", "2024"),
        "ctc": sim.calculate("ctc", "2024"),
        "eitc": sim.calculate("eitc", "2024")
    })

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 hello@policyengine.org 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_amount"
)
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 (don't include personal info in reforms)

### Performance

**API calls:**
- Simple household: ~200-500ms
- Population impact: ~5-30 seconds (varies by reform)
- Use caching for repeated calculations

**Local simulation (policyengine-us):**
- Faster for batch analysis
- No rate limits
- No network dependency
- Limited to one country per package

## Choosing Local vs API

### Use Local (policyengine-us package)

**When:**
- Batch analysis of many households
- Need offline capability
- Analyzing parameter sweeps (axes)
- Development/testing

**Install:**
```bash
pip install policyengine-us  # US only
pip install policyengine-uk  # UK only
```

**Example:**
```python
from policyengine_us import Simulation

# Works offline
sim = Simulation(situation=household)
```

### Use API (policyengine or requests)

**When:**
- Multi-country analysis
- Using latest model version
- Don't want to manage dependencies
- Integration with web services

**Example:**
```python
import requests

# Requires internet
response = requests.post("https://api.policyengine.org/us/calculate", ...)
```

## For Contributors: Understanding the Client

**Repository:** PolicyEngine/policyengine.py

**To see implementation:**
```bash
# Clone the client
git clone https://github.com/PolicyEngine/policyengine.py

# See the Simulation class
cat policyengine/simulation.py

# See API integration
cat policyengine/api.py
```

**Architecture:**
- `Simulation` class wraps API calls
- `calculate()` method handles caching
- Transparent fallback between API and local

## Advanced: Direct Country Package Usage

For maximum control and performance, use country packages directly:

```python
from policyengine_us import Simulation

# Full control over situation structure
situation = {
    # Complete situation dictionary
    # See policyengine-us-skill for patterns
}

sim = Simulation(situation=situation)
result = sim.calculate("variable_name", 2024)
```

**Benefits:**
- No API dependency
- Faster (no network)
- Full access to all variables
- Use axes for parameter sweeps

**See policyengine-us-skill for detailed patterns.**

## Examples and Tutorials

**PolicyEngine documentation:**
- US: https://policyengine.org/us/docs
- UK: https://policyengine.org/uk/docs

**Example notebooks:**
- Repository: PolicyEngine/analysis-notebooks
- See policyengine-analysis-skill for analysis patterns

**Community examples:**
- Blog posts: policyengine.org/us/research
- GitHub discussions: github.com/PolicyEngine discussions

## Getting Help

**For usage questions:**
- GitHub Discussions: https://github.com/PolicyEngine/policyengine-us/discussions

**For bugs:**
- File issues in appropriate repo (policyengine-us, policyengine.py, etc.)

**For collaboration:**
- Email: hello@policyengine.org

