# Python SDK

The official Python client for the Cubit API.

## Installation

```bash
pip install cubit-api
```

**Requirements:**

* Python 3.8+
* httpx >= 0.24.0

## Quick Start

```python
from cubit import CubitClient

# Initialize with your API key
client = CubitClient("cubit_your_api_key")

# Search for jobs
results = client.search_jobs("software developer")
for job in results["jobs"]:
    print(f"{job['title']}: {job['balanced_impact_score']}")

# Get a specific job profile
job = client.get_job("15-1252.00")
print(f"Automation Risk: {job['scores']['automation_susceptibility_score']}")

# Clean up
client.close()
```

## Client Initialization

```python
from cubit import CubitClient

client = CubitClient(
    api_key="cubit_your_api_key",
    base_url="https://api.maidenlabs.tools",  # Optional: override base URL
    timeout=30.0,  # Optional: request timeout in seconds
)
```

### Using Environment Variables

```python
import os
from cubit import CubitClient

client = CubitClient(os.environ["CUBIT_API_KEY"])
```

## Context Manager

The SDK supports context manager pattern for automatic cleanup:

```python
from cubit import CubitClient

with CubitClient("cubit_your_api_key") as client:
    job = client.get_job("15-1252.00")
    print(job["title"])
# Connection automatically closed
```

***

## Method Reference

### Utility Methods

#### `health()`

Check API health status. No authentication required.

```python
status = client.health()
print(status["status"])  # "healthy"
print(status["version"])  # "2.0.0"
```

#### `me()`

Get information about the current API key.

```python
info = client.me()
print(f"Tier: {info['tier']}")
print(f"Remaining requests: {info['rate_limit']['remaining']}")
```

#### `schema()`

Get data schema and field definitions.

```python
schema = client.schema()
print(schema["dimensions"])
print(schema["quadrants"])
```

#### `stats_overview()`

Get aggregate statistics about the dataset.

```python
stats = client.stats_overview()
print(f"Total occupations: {stats['total_occupations']}")
print(f"Total tasks: {stats['total_tasks']}")
```

***

### Job Methods

#### `search_jobs(query, limit=10, exposure_threshold=None, imperative_threshold=None)`

Search jobs by keyword (title matching).

**Access:** All tiers

**Parameters:**

* `query` (str): Search query for job title
* `limit` (int): Max results (1-50, default 10)
* `exposure_threshold` (float): Threshold for "high exposure" quadrant (0.0-1.0, default 0.5)
* `imperative_threshold` (float): Threshold for "high imperative" quadrant (0.0-1.0, default 0.5)

```python
results = client.search_jobs("nurse", limit=5)
for job in results["jobs"]:
    print(f"{job['title']}: {job['soc_code']}")

# With custom thresholds
results = client.search_jobs("clerk", exposure_threshold=0.45)
```

#### `search_jobs_semantic(query, limit=10, search_scope="jobs")`

Search using natural language queries.

**Access:** Enterprise only

```python
results = client.search_jobs_semantic(
    "careers for people who like animals and outdoors",
    limit=10,
    search_scope="jobs"  # or "tasks" or "both"
)
for job in results["jobs"]:
    print(f"{job['title']} ({job['relevance_score']:.0%} match)")
```

#### `get_job(soc_code, exposure_threshold=None, imperative_threshold=None)`

Get complete profile for a job.

**Access:** All tiers (response depth varies)

**Parameters:**

* `soc_code` (str): O\*NET SOC code (e.g., "15-1252.00")
* `exposure_threshold` (float): Threshold for "high exposure" quadrant (0.0-1.0, default 0.5)
* `imperative_threshold` (float): Threshold for "high imperative" quadrant (0.0-1.0, default 0.5)

```python
job = client.get_job("15-1252.00")
print(job["title"])
print(job["scores"]["balanced_impact_score"])
print(job["classification"]["quadrant"])

# With custom thresholds
job = client.get_job("43-3031.00", exposure_threshold=0.45)
print(job["classification"]["quadrant"])  # May now be "automation"

# Professional tier includes keystone_skills
if "keystone_skills" in job:
    for skill in job["keystone_skills"][:3]:
        print(f"  {skill['name']}: {skill['ai_resilience']}% resilient")
```

#### `get_job_tasks(soc_code, sort_by, sort_order, limit, include_explanations, exposure_threshold=None, imperative_threshold=None)`

Get all tasks for a job with dimension scores.

**Access:** Professional, Enterprise

**Parameters:**

* `soc_code` (str): O\*NET SOC code
* `sort_by` (str): Sort field (default: "ai\_exposure\_potential")
* `sort_order` (str): "asc" or "desc" (default: "desc")
* `limit` (int): Max tasks (1-100, default 50)
* `include_explanations` (bool): Include dimension explanations (default: True)
* `exposure_threshold` (float): Threshold for "high exposure" quadrant (0.0-1.0, default 0.5)
* `imperative_threshold` (float): Threshold for "high imperative" quadrant (0.0-1.0, default 0.5)

```python
tasks = client.get_job_tasks(
    "15-1252.00",
    sort_by="ai_exposure_potential",
    sort_order="desc",
    limit=20,
    include_explanations=True
)

for task in tasks["tasks"]:
    print(f"{task['task'][:60]}...")
    print(f"  Exposure: {task['pillars']['ai_exposure_potential']:.0%}")
    print(f"  Quadrant: {task['quadrant']}")
```

#### `get_job_requirements(soc_code, type, source, limit)`

Get skill requirements for a job.

**Access:** Professional, Enterprise

```python
reqs = client.get_job_requirements(
    "15-1252.00",
    type="skills",  # or "abilities", "knowledge", "all"
    source="keystone",  # or "diagnostics"
    limit=10
)

for req in reqs["requirements"]:
    print(f"{req['name']}: {req['ai_resilience_score']:.0%} resilient")
```

#### `explain_job(soc_code)`

Get methodology explanation for a job's scores.

**Access:** Professional, Enterprise

```python
explanation = client.explain_job("15-1252.00")
print(explanation["score_breakdown"]["balanced_impact_score"]["formula"])
print(explanation["data_sources"])
```

#### `compare_jobs(soc_codes, exposure_threshold=None, imperative_threshold=None)`

Compare multiple jobs side-by-side.

**Access:** Professional, Enterprise

**Parameters:**

* `soc_codes` (List\[str]): List of SOC codes to compare (2-10 jobs)
* `exposure_threshold` (float): Threshold for "high exposure" quadrant (0.0-1.0, default 0.5)
* `imperative_threshold` (float): Threshold for "high imperative" quadrant (0.0-1.0, default 0.5)

```python
result = client.compare_jobs(["15-1252.00", "29-1141.00", "43-3031.00"])
for job in result["comparison"]:
    print(f"{job['title']}: {job['balanced_impact_score']:+.0f}")
print(result["skill_overlap_matrix"])
```

***

### Skill Methods

#### `list_skills(type, sort_by, limit)`

List all skills/abilities/knowledge.

**Access:** All tiers

```python
skills = client.list_skills(
    type="skills",  # or "abilities", "knowledge", "all"
    sort_by="ai_resilience_score",
    limit=20
)

for skill in skills["requirements"]:
    print(f"{skill['name']}: {skill['ai_resilience_score']:.0%}")
```

#### `get_skill(element_id)`

Get detailed profile for a skill.

**Access:** Professional, Enterprise

```python
skill = client.get_skill("2.B.3.e")  # Programming
print(f"AI Resilience: {skill['ai_resilience_score']:.0%}")
print(f"Benchmark coverage: {skill['benchmark_coverage']['total_benchmarks']}")
```

#### `search_skills_semantic(query, limit)`

Search skills using natural language.

**Access:** Enterprise only

```python
results = client.search_skills_semantic("ability to convince others")
for skill in results["requirements"]:
    print(f"{skill['name']} ({skill['similarity']:.0%} match)")
```

#### `analyze_skill_gap(current_skills, target_job)`

Analyze skill gaps for career transition.

**Access:** Professional, Enterprise

```python
gap = client.analyze_skill_gap(
    current_skills=["Programming", "Critical Thinking"],
    target_job="13-2011.00"
)
print(f"Coverage: {gap['skill_coverage']:.0%}")
for skill in gap["gap_skills"][:3]:
    print(f"  Need: {skill['name']} ({skill['priority']})")
```

***

### Region Methods

#### `list_regions(state, min_employment, sort_by, limit)`

List MSA regions with risk metrics.

**Access:** Enterprise only

```python
regions = client.list_regions(
    state="CA",
    min_employment=100000,
    sort_by="total_at_risk_wages",
    limit=20
)

for region in regions["regions"]:
    print(f"{region['msa_name']}: ${region['total_at_risk_wages']:,.0f}")
```

#### `get_region(msa_code, include_jobs, job_limit)`

Get detailed profile for a region.

**Access:** Enterprise only

```python
region = client.get_region("31080", include_jobs=True, job_limit=20)
print(f"Employment: {region['summary']['total_employment']:,}")
print(f"At-risk jobs: {region['summary']['total_at_risk_jobs']:,}")
```

***

### Enterprise Methods

#### `calculate_custom_score(weights, jobs, aggregation)`

Calculate custom scores with your dimension weights.

**Access:** Enterprise only

```python
result = client.calculate_custom_score(
    weights={
        "procedural": 0.5,
        "digitization": 0.3,
        "physicality": -0.8,
        "socio_emotional": -0.5
    },
    jobs=["15-1252.00", "29-1141.00"],
    aggregation="weighted_mean"
)

for job in result["results"]:
    print(f"{job['title']}: {job['custom_score']:.1f} (vs {job['standard_score']:.1f})")
```

#### `batch_lookup(soc_codes, fields, format)`

Batch retrieve job profiles.

**Access:** Enterprise only

```python
batch = client.batch_lookup(
    soc_codes=["15-1252.00", "29-1141.00", "43-3031.00"],
    fields=["scores", "keystone_skills"]
)

for job in batch["jobs"]:
    print(job["title"])
```

#### `find_transitions(source_soc, similarity_threshold, max_results, filters)`

Find career transition pathways.

**Access:** Enterprise only

```python
transitions = client.find_transitions(
    source_soc="43-3031.00",
    similarity_threshold=0.7,
    max_results=10,
    filters={
        "min_resilience_gain": 10,
        "require_positive_growth": True
    }
)

for t in transitions["transitions"]:
    print(f"-> {t['target_title']}: +{t['resilience_gain']:.0f} resilience")
    print(f"  Skills to develop: {', '.join(t['gap_skills'][:3])}")
```

#### `list_benchmarks(skill, benchmark, limit, offset)`

List AI benchmark evaluations.

**Access:** Enterprise only

```python
benchmarks = client.list_benchmarks(skill="Programming", limit=20)
for b in benchmarks["benchmarks"]:
    print(f"[{b['benchmark_name']}] {b['task_description'][:60]}...")
```

#### `get_benchmark(input_id)`

Get benchmark detail.

**Access:** Enterprise only

```python
benchmark = client.get_benchmark("12345")
print(benchmark["task_description"])
for skill in benchmark["skills_tested"]:
    print(f"  {skill['name']}: {skill['relevance_score']:.0%}")
```

***

## Type Hints

The SDK includes full type annotations. All methods return `TypedDict` responses for IDE autocompletion:

```python
from cubit import CubitClient
from cubit.models import JobProfile, JobSearchResponse

client = CubitClient("cubit_key")

# Type hints work with autocomplete
job: JobProfile = client.get_job("15-1252.00")
results: JobSearchResponse = client.search_jobs("nurse")
```

***

## Next Steps

* [Async Client](/sdk-reference/async-client.md) - Asynchronous version for high-throughput
* [Error Handling](/sdk-reference/errors.md) - Exception types and handling patterns


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.maidenlabs.tools/sdk-reference/python.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
