Metadata-Version: 2.4
Name: minerva-sdk
Version: 0.0.7
Summary: Official Python SDK for the Minerva Data API — resolve, enrich, validate, usage.
Project-URL: Documentation, https://docs.minerva.io/sdk/introduction
Author: Minerva Data
License: MIT
License-File: LICENSE
Keywords: enrichment,identity-resolution,minerva
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic<3,>=2.6
Provides-Extra: all
Requires-Dist: pandas>=2; extra == 'all'
Requires-Dist: tabulate>=0.9; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: pandas
Requires-Dist: pandas>=2; extra == 'pandas'
Provides-Extra: table
Requires-Dist: tabulate>=0.9; extra == 'table'
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://app.minerva.io/logo-wordmark.svg" alt="Minerva" width="220">
</p>

# Minerva SDK

The official Python SDK for the Minerva Data API —
identity **resolution**, person **enrichment**, and validation, with one client, typed responses,
and input validation baked in.

![Python](https://img.shields.io/badge/python-3.11%E2%80%933.14-blue)
![Types](https://img.shields.io/badge/typed-pydantic%20v2-blue)

```python
from minerva import Minerva

mc = Minerva()  # reads MINERVA_API_KEY from the environment

results = mc.api.enrich([{"record_id": "1", "linkedin_url": "https://www.linkedin.com/in/example"}])
df = results.to_df()        # straight to a DataFrame
```

> **Early access.** Data API surface — resolve, enrich, LinkedIn lookup, email validation,
> country inference, and usage tallies — is wired and tested.

---

## Installation

```bash
pip install minerva-sdk
```

Optional extras:

```bash
pip install "minerva-sdk[pandas]"   # results.to_df()
pip install "minerva-sdk[table]"    # results.to_table()
pip install "minerva-sdk[all]"      # everything
```

Requires **Python 3.11+** (tested through 3.14).

---

## Authentication

`Minerva` is the single entry point. The only credential you need is your **API key**:

| Variable | Used for |
|---|---|
| `MINERVA_API_KEY` | every call the SDK makes |

```python
mc = Minerva()                          # api_key from MINERVA_API_KEY
mc = Minerva(api_key="mk_live_...")     # explicit
```

The SDK sends the API key as the `x-api-key` header on every request. The server-side authorizer
decides what your key is entitled to.

---

## Quickstart

```python
from minerva import Minerva

mc = Minerva(api_key="mk_live_...")

# Resolve — match records to a Minerva PID
mc.api.resolve([{"record_id": "1", "first_name": "Jane", "last_name": "Doe",
                 "emails": ["jane.doe@example.com"]}])

# Enrich — full profiles (up to 500 records per call)
resp = mc.api.enrich(
    [{"record_id": "1", "linkedin_url": "https://www.linkedin.com/in/example"}],
    match_condition_fields=["linkedin_url"],   # only count it a match if a LinkedIn URL is on file
)
for r in resp.results:
    print(r.record_id, r.is_match, r.minerva_pid, r.match_score)

# Tabular output
resp.to_df()            # pandas DataFrame   (needs [pandas])
resp.to_csv("out.csv")  # write a CSV
resp.to_dicts()         # list[dict]
```

---

## Validate before you call — `dry_run`

Every input-bearing method takes `dry_run=True`. It validates your input **locally** and returns
the exact request that *would* be sent — **without touching the network**. Invalid input raises
`MinervaValidationError` immediately, with a precise field message.

```python
from minerva import Minerva, MinervaValidationError

mc = Minerva()

req = mc.api.enrich(records, match_condition_fields=["linkedin_url"], dry_run=True)
# -> EnrichRequest (nothing sent). Inspect req.model_dump() to see the payload.

try:
    mc.api.enrich([], dry_run=True)     # 0 records — must be at least 1
except MinervaValidationError as e:
    print("caught before any API call:", e)
```

Great for checking a batch is well-formed (record limits, allowed `match_condition_fields`,
record shape, …) before spending a call.

---

## What you can do

| Namespace | Highlights |
|---|---|
| `mc.api` | `resolve`, `enrich`, `get_li_contact_info`, `validate_emails`, `infer_record_country`, `call` |
| `mc.usage` | `tallies()` — your per-endpoint API usage |

Every response is a typed model with IDE autocomplete, and the list-shaped ones support
`.to_df()` / `.to_csv()` / `.to_dicts()` / `.to_table()`.

---

## Custom / tailored endpoints — `mc.api.call`

For client-specific routes (preview endpoints, partner integrations, paths Minerva built just
for your org) on the Data API, use the generic `mc.api.call`:

```python
result = mc.api.call("POST", "/v2/acme/lookup", json={"record_id": "abc"})
```

Same `x-api-key` auth, same error mapping, same rate-limit handling as the typed methods — the
difference is the SDK doesn't know the response schema, so you get back the raw parsed JSON.
The server enforces entitlement; callers without it see a 403 → `MinervaAuthError`.

---

## Error handling

All errors derive from `MinervaError`:

```python
from minerva import (
    MinervaValidationError,  # bad input — raised locally, before the call
    MinervaAuthError,        # 401/403 — bad key, not entitled
    MinervaRateLimitError,   # 429 — has .retry_after
    MinervaAPIError,         # other 4xx/5xx — has .status_code and .api_request_id
)

try:
    mc.api.enrich(records)
except MinervaRateLimitError as e:
    time.sleep(e.retry_after or 1)
except MinervaAPIError as e:
    print("request failed:", e.api_request_id)   # quote this to support
```

Responses are forward-compatible: new fields the API adds won't break an older client.

---

## Python support

3.11, 3.12, 3.13, 3.14. Fully type-annotated (ships `py.typed`).

## License

[MIT](LICENSE) © Minerva Data.
