> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minerva.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom & tailored endpoints

> Escape hatch for client-specific endpoints — preview routes, partner integrations, anything not yet wrapped in a typed SDK method.

The typed methods (`mc.api.enrich` / `mc.api.resolve` / …) cover the public
Minerva Data API. For **client-specific** routes — preview endpoints, partner
integrations, a path Minerva built just for your org — use `mc.api.call(...)`
directly.

```python theme={null}
result = mc.api.call("POST", "/v2/acme/lookup", json={"record_id": "abc"})
# {"matches": [{"id": "p-1", ...}]}
```

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 (typically a dict).

## When to reach for it

| You're calling…                                          | Use                                                                                                         |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `/v2/enrich`, `/v2/resolve`, `/v2/validate_emails`, etc. | The typed method (`mc.api.enrich(...)`, `mc.api.resolve(...)`, …) — pydantic in, pydantic out, autocomplete |
| A path tailored to your org (e.g. `/v2/acme/...`)        | `mc.api.call(...)`                                                                                          |
| A preview endpoint not yet promoted to the typed API     | `mc.api.call(...)`                                                                                          |

<Tip>
  If you find yourself calling the same custom endpoint a lot, ask us to add a
  typed wrapper. Typed wrappers get autocomplete, schema validation, and
  tabular response helpers for free.
</Tip>

## Authentication & entitlement

Entitlement is enforced **server-side**. Your `x-api-key` is checked against
an allow-list of paths per request — callers without entitlement get a 403,
which the SDK surfaces as `MinervaAuthError`:

```python theme={null}
from minerva import MinervaAuthError

try:
    mc.api.call("POST", "/v2/acme/internal", json={...})
except MinervaAuthError:
    print("your key isn't entitled to this endpoint — contact your Minerva rep")
```

There's nothing special on the SDK side — same auth path as `mc.api.enrich(...)`.

## Parameters

<ParamField path="method" type="str" required>
  HTTP verb: `"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, `"PATCH"`. Case-insensitive.
</ParamField>

<ParamField path="path" type="str" required>
  URL path beginning with `/`, e.g. `"/v2/acme/lookup"`.
</ParamField>

<ParamField path="params" type="dict">
  Optional query-string dict. Values are URL-encoded for you.
</ParamField>

<ParamField path="json" type="Any">
  Optional JSON body (for POST/PUT/PATCH). Typically a `dict`.
</ParamField>

<ParamField path="headers" type="dict[str, str]">
  Optional extra request headers — merged on top of the SDK's defaults. The
  `x-api-key` header is always set by the SDK and can't be overridden here.
</ParamField>

## Return value

The parsed JSON response body — whatever shape the endpoint returns. **No
pydantic validation** is applied (the SDK doesn't know the schema); validate
yourself if it matters:

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

from pydantic import BaseModel

class AcmeMatch(BaseModel):
    id: str
    score: float

matches = [AcmeMatch(**m) for m in result["matches"]]
```

## Errors

| Status                                      | Raises                                                 |
| ------------------------------------------- | ------------------------------------------------------ |
| Local — bad `path` (empty / no leading `/`) | `MinervaValidationError`                               |
| 401 / 403                                   | `MinervaAuthError`                                     |
| 429                                         | `MinervaRateLimitError(retry_after=...)`               |
| Other 4xx / 5xx                             | `MinervaAPIError(status_code=..., api_request_id=...)` |

## Examples

**GET with query string:**

```python theme={null}
mc.api.call("GET", "/v2/acme/audit", params={"since": "2026-05-01", "limit": 100})
```

**POST with body + custom header for tracing:**

```python theme={null}
mc.api.call(
    "POST",
    "/v2/acme/lookup",
    json={"record_id": "abc"},
    headers={"X-Trace-Id": "tr-123"},
)
```

**DELETE:**

```python theme={null}
mc.api.call("DELETE", "/v2/acme/records/abc")
```
