> For the complete documentation index, see [llms.txt](https://docs.moderncollections.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.moderncollections.io/sdks/python.md).

# Python SDK

A real Python client now exists: **`mc_api.client.MCClient`**.

It is a hardened, typed, synchronous HTTP client over the Modern Collections **external REST API** (the creditor-API-key surface). The same client backs two front-ends that ship in the same package — a CLI (`mc-api`) and an MCP stdio server (`mc-api-mcp`) — so the library, the CLI, and your agent tools all hit the exact same code path.

{% hint style="warning" %}
**Not on PyPI yet.** There is **no `moderncollections` (or `mc-api`) package on PyPI** — do not `pip install mc-api` from the public index. The package is distributed by Modern Collections during onboarding. The import name is `mc_api`; the current package version is `0.1.0`.
{% endhint %}

## Install

Install the package provided by your Modern Collections onboarding contact into your virtual environment:

```bash
pip install ./mc_api      # path to the provided package
```

This installs the `mc_api` import package plus two console scripts: `mc-api` (CLI) and `mc-api-mcp` (MCP server).

## Configure

The client is configured entirely through constructor arguments or environment variables. Pick an environment **explicitly** — there is **no production default**, by design, so a forgotten flag can never silently point a test key at production.

| Variable          | Values                                          |
| ----------------- | ----------------------------------------------- |
| `MC_API_ENV`      | `demo` \| `prod`                                |
| `MC_API_BASE_URL` | explicit base URL (overrides `MC_API_ENV`)      |
| `MC_API_KEY`      | creditor API key, format `ca_<prefix>_<secret>` |

Environment → base URL map (every versioned route is served under `/v1`):

| env    | base URL                                |
| ------ | --------------------------------------- |
| `demo` | `https://app.demo.moderncollections.io` |
| `prod` | `https://api.moderncollections.io`      |

{% hint style="info" %}
On `demo`, the bare `/health` route belongs to the dashboard origin, **not** the API — but authenticated `/v1/*` calls (everything the client does) reach the backend normally.
{% endhint %}

Resolution precedence is: explicit `base_url=` > explicit `env=` > `MC_API_BASE_URL` > `MC_API_ENV`. If nothing selects a target, the client raises `ValueError` rather than falling back to production.

## Quickstart

`MCClient` is a context manager. Construct it with an environment name (or explicit base URL) plus a creditor key, then call typed methods.

```python
from mc_api import MCClient

with MCClient(env="demo", api_key="ca_...") as api:
    # Create a placement: an overdue invoice handed to us for collection.
    placement = api.create_placement({
        "invoice_amount": "7500.00",
        "debtor": {
            "company_name": "Acme Freight",
            "primary_email": "ap@acme.co",
        },
    })

    placement_id = placement["placement_id"]

    # Read it back.
    current = api.get_placement(placement_id)
    print(current["status"])
```

If you omit `api_key=` and have not set `MC_API_KEY`, the client still constructs (so the unauthenticated `health()` reachability check works), but any authenticated call fails fast client-side with a clear `ValueError` before a request is sent.

### Constructor

```python
MCClient(
    *,
    env: str | None = None,        # demo | prod
    base_url: str | None = None,   # overrides env
    api_key: str | None = None,    # falls back to MC_API_KEY
    timeout: float = 30.0,         # read + write timeout, seconds
    max_retries: int = 2,          # GET-only retry budget
)
```

### Selected methods

| Method                                               | Route                                          |
| ---------------------------------------------------- | ---------------------------------------------- |
| `create_placement(payload)`                          | `POST /v1/placements`                          |
| `get_placement(id)`                                  | `GET /v1/placements/{id}`                      |
| `list_placements(page=, page_size=, status=)`        | `GET /v1/placements`                           |
| `record_payment(id, amount=)`                        | `POST /v1/placements/{id}/payment-received`    |
| `get_dispute(id)` / `acknowledge_dispute(id, note=)` | `GET` / `POST .../dispute[...]`                |
| `get_audit(id, event_type=, cursor=, limit=)`        | `GET /v1/placements/{id}/audit`                |
| `analytics_summary()`                                | `GET /v1/analytics/summary`                    |
| `health(deep=)`                                      | `GET /health` (unversioned reachability probe) |

All requests send `Authorization: Bearer ca_<prefix>_<secret>` on the versioned routes.

### Errors

Every non-2xx response (and every transport failure) raises `mc_api.ApiError`, which carries `status_code`, the server's opaque `detail` string, and the request `url`. Transport failures (timeout, connection refused) surface as `ApiError` with `status_code == 0`. The exception **never** contains the bearer token.

```python
from mc_api import ApiError

try:
    api.get_placement("does-not-exist")
except ApiError as exc:
    print(exc.status_code, exc.detail)   # e.g. 404 "placement not found"
```

## Safety properties

The client is built to be safe to run from agents and CI without leaking credentials or duplicating side effects:

* **Secret redaction** — the API key lives only in the request `Authorization` header. It is deliberately excluded from `repr()`, exceptions, and logs. `repr(MCClient(...))` prints only the API base URL, never the key.
* **Explicit timeouts** — connect, read, write, and pool timeouts are all bounded. The `timeout=` argument sets the read/write budget (default 30s).
* **GET-only retries** — only idempotent methods (`GET`/`HEAD`/`OPTIONS`) are retried, and only on `429`/`502`/`503`/`504` with exponential backoff (0.25s, 0.5s, 1s … capped at 5s). `POST`/`PATCH`/`DELETE` are **never** auto-retried, so a `create_placement` or `record_payment` can't be silently duplicated.
* **No production default** — you must choose an environment explicitly. A missing selection raises `ValueError`; it never falls back to `prod`.
* **No redirect following** — `follow_redirects=False`, so a misconfigured host can't bounce an authenticated request somewhere unexpected.

## CLI (`mc-api`)

The same package installs an `mc-api` console script. Global options (`--env` / `--base-url` / `--api-key` / `--output` / `--timeout`) precede the subcommand; `-o`/`--output` is `table` (default) or `json`.

```bash
export MC_API_ENV=prod MC_API_KEY=ca_...

mc-api health                                   # reachability probe
mc-api placements create --company "Acme Freight" --amount 7500.00 --email ap@acme.co
mc-api placements list --status in_outreach
mc-api placements get <placement_id>
mc-api payments record <placement_id> --amount 500.00
mc-api disputes ack <placement_id> --note "spoke with AP"
mc-api analytics summary -o json
```

**Exit codes:** `0` success, `1` API/runtime error, `2` configuration/usage error.

## MCP server (`mc-api-mcp`)

The package also installs `mc-api-mcp`, a Model Context Protocol stdio server exposing the same endpoints as agent tools. Configure it with the same `MC_API_ENV` / `MC_API_KEY` environment variables and register it with an MCP client:

```bash
claude mcp add modern-collections -- mc-api-mcp
# then set MC_API_ENV / MC_API_KEY in the server's environment
```

It currently exposes exactly **8** tools (snake\_case): `placement_create`, `placement_status`, `placement_list`, `payment_record`, `dispute_get`, `dispute_acknowledge`, `audit_query`, `analytics_summary`.

See the [MCP server overview](/mcp-servers/overview.md) and [installation](/mcp-servers/installation.md) for the agent-facing reference.

## Reference

* The canonical, field-accurate contract is the generated OpenAPI spec at [`api-reference/rest-api/openapi.yaml`](/rest-api/overview.md) — produced directly from the live API (62 paths / 71 operations).

## See also

* [REST API overview](/rest-api/overview.md) and [Placements](/rest-api/placements.md)
* [MCP server overview](/mcp-servers/overview.md) / [installation](/mcp-servers/installation.md)
* [Authentication](/getting-started/authentication.md) and [Environments](/getting-started/environments.md)
* [JavaScript SDK](/sdks/javascript.md)
* [Generate your own client (codegen)](/sdks/codegen.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.moderncollections.io/sdks/python.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
