---
title: "Python"
description: "The mentio package, one call per endpoint, sync and async."
canonical: https://docs.mentio.dev/sdks/python
markdown: https://docs.mentio.dev/sdks/python.mdx
---

# Python

The mentio package, one call per endpoint, sync and async.

`mentio` is the Mentio API in Python: one object, one call per endpoint, grouped by resource, with typed models for every response. It is generated from the same OpenAPI document as the [API Reference](/api) and regenerated whenever the API changes. Python 3.11 or newer; `httpx` underneath, sync and async.

```bash
pip install mentio
```

## Use it

```python
from mentio import Mentio

mentio = Mentio(api_key="mk_live_...")

page = mentio.mentions.search(platform="reddit", relevant=True, limit=25)
for mention in page.data:
    print(mention.post.platform.value, mention.classification.relevance, mention.post.url)
```

Every call returns the parsed response: the model for the endpoint (`page.data`, `page.next_cursor`), a `str` for CSV exports, `None` for a 204. Anything but a 2xx raises `MentioError` with the API's `status`, `code` and `message`:

```python
from mentio import MentioError

try:
    mentio.keywords.create(term="a")
except MentioError as err:
    print(err.status, err.code, err.message)   # 400 validation_error term: String must contain at least 2 character(s)
```

## Every endpoint, the same way

Ids are positional. Filters are keyword arguments named as in the API, in snake\_case (`keyword_ids`, `min_relevance`); the two that collide with Python names are `range_` and `from_`. Bodies take their fields as keyword arguments, a dict, or a model:

```python
mentio.keywords.create(term="acme", kind="brand", platforms=["reddit", "hackernews"])
mentio.keywords.update("kw_60d9...", muted=True)
mentio.mentions.update("mm_7f3a...", status="done", note="Replied in the thread")
mentio.people.merge("aut_1c2d...", into="aut_9e0f...")
mentio.channels.create(kind="webhook", url="https://example.com/hooks/mentio", label="Production")
mentio.alerts.create(
    name="Negative mentions", mode="instant", event="mention.negative",
    filter={"sentiments": ["negative"]}, channel_ids=["dest_..."],
)
mentio.analytics.summary(range_="7d", compare=True, timezone="Europe/Madrid")
mentio.analytics.breakdown(by="hour", range_="30d")
```

Enum-valued arguments take plain strings (`platform="reddit"`); the generated enums under `mentio.models` work too. Instants (`since`, `until`, `snoozed_until`) take a `datetime`, a `date`, an ISO 8601 string or epoch milliseconds.

Page a list by passing `next_cursor` back as `cursor` until it is `None`:

```python
cursor = None
while True:
    page = mentio.mentions.search(relevant=True, limit=100, cursor=cursor)
    for mention in page.data:
        handle(mention)
    if page.next_cursor is None:
        break
    cursor = page.next_cursor
```

CSV exports come back as text:

```python
csv = mentio.mentions.export(since="2026-09-01", platform="reddit")
open("mentions.csv", "w").write(csv)
```

## Async

`AsyncMentio` mirrors every call:

```python
import asyncio
from mentio import AsyncMentio

async def main() -> None:
    async with AsyncMentio(api_key="mk_live_...") as mentio:
        summary = await mentio.analytics.summary(range_="7d")
        print(summary.matched, summary.relevant)

asyncio.run(main())
```

## Groups

| Attribute   | Calls                                                                              |
| ----------- | ---------------------------------------------------------------------------------- |
| `keywords`  | `list`, `get`, `create`, `update`, `delete`                                        |
| `mentions`  | `search`, `get`, `update`, `export`                                                |
| `people`    | `list`, `get`, `update`, `merge`, `split`, `export`                                |
| `segments`  | `list`, `get`, `create`, `update`, `delete`                                        |
| `alerts`    | `list`, `get`, `create`, `update`, `delete`, `test`, `run`                         |
| `channels`  | `list`, `get`, `create`, `update`, `delete`, `test`, `rotate_secret`, `deliveries` |
| `company`   | `get`, `update`                                                                    |
| `analytics` | `summary`, `series`, `breakdown`, `share_of_voice`                                 |
| `api_keys`  | `list`, `create`, `revoke`                                                         |
| `system`    | `health`                                                                           |

## Under the hood

`mentio.client` is the generated `AuthenticatedClient` (an `httpx` client with the key), and `mentio.api.<group>.<operation>` are the generated per-operation modules with full signatures (`mentio.api.mentions.search_mentions.sync_detailed(...)` returns the raw `Response`). Use them when you need headers, status codes or an `httpx` feature the facade does not expose.

```python
mentio = Mentio(api_key, base_url="https://api.mentio.internal", timeout=10.0, headers={"x-request-source": "billing-job"})
```
