Metadata-Version: 2.4
Name: maton-ai
Version: 0.1.0
Summary: Official Python SDK for Maton — connect and automate 150+ apps.
Project-URL: Homepage, https://maton.ai
Project-URL: Documentation, https://github.com/maton-ai/maton-py#readme
Project-URL: Repository, https://github.com/maton-ai/maton-py
Project-URL: Issues, https://github.com/maton-ai/maton-py/issues
Project-URL: Changelog, https://github.com/maton-ai/maton-py/blob/main/CHANGELOG.md
Author: Maton
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Keywords: ai-agents,api-gateway,integrations,maton,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: typing-extensions>=4.7.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.5; extra == 'dev'
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# maton-ai

Official Python SDK for [Maton](https://maton.ai) — connect and automate 150+
apps (Gmail, Slack, GitHub, Notion, HubSpot, Airtable, and more) from Python.

> **Status: Alpha.** Pre-1.0 releases may break action method shapes and error
> types between minor versions. Pin exactly (`maton-ai==0.1.0`) until 1.0.

## Install

From PyPI (once published):

```bash
pip install maton-ai
```

From GitHub (alpha / preview):

```bash
pip install "maton-ai @ git+https://github.com/maton-ai/maton-py@main"
```

Requires Python 3.10+.

## Quickstart

```python
import os
from maton_ai import Maton

maton = Maton(api_key=os.environ["MATON_API_KEY"])

conn = maton.connection.create(app="gmail")
connection_id = conn["id"]

gmail = maton.google_mail(connection=connection_id)
messages = gmail.message.list(q="is:unread", max_results=10)
gmail.message.send(to="alice@example.com", subject="hi", body="hello")
```

The same pattern works for every supported app:

```python
slack = maton.slack(connection=slack_conn_id)
slack.message.send(channel="#general", text="deploy finished ✅")

gh = maton.github(connection=gh_conn_id)
gh.issue.create(repo="maton-ai/maton-py", title="bug: ...", body="...")

notion = maton.notion(connection=notion_conn_id)
notion.data_source.query(data_source_id="...", filter={"property": "Status", "status": {"equals": "Done"}})

hubspot = maton.hubspot(connection=hubspot_conn_id)
hubspot.contact.list(limit=25)
```

There are three places to select a connection, in order of precedence
(per-call beats accessor beats constructor):

```python
maton = Maton(api_key=..., connection=connection_id)

gmail = maton.google_mail(connection=connection_id)
gmail.message.list(q="is:unread")

maton.google_mail.message.list(q="is:unread", connection=connection_id)
```

Generic passthrough:

```python
maton.api.post(
    "google-mail",
    "/gmail/v1/users/me/messages/send",
    json={"raw": "..."},
    connection=connection_id,
)
```

## Triggers

Triggers register an event source (e.g. GitHub `pull_request.opened`) and fan
matching events out to webhook destinations. Manage them through
`maton.trigger`, with `maton.trigger.destination` and `maton.trigger.event`
sub-resources:

```python
trigger = maton.trigger.create(
    source="github",
    event_type="pull_request.opened",
    connection_id=gh_conn_id,
    parameters={"repo": "maton-ai/cli"},
    destinations=[{"url": "https://example.com/hook"}],
)
trigger_id = trigger["trigger"]["trigger_id"]

maton.trigger.list(source="github", status="ENABLED")
maton.trigger.update(trigger_id, status="DISABLED")

dst = maton.trigger.destination.create(trigger_id, url="https://example.com/hook")
maton.trigger.destination.rotate_secret(trigger_id, dst["destination"]["destination_id"])

events = maton.trigger.event.list(trigger_id, limit=20)
maton.trigger.event.replay(trigger_id, events["events"][0]["event_id"])

for event in maton.trigger.event.watch(trigger_id):
    handle(event)
```

## Supported apps (v0.1)

| App | Accessor | Highlights |
|---|---|---|
| Asana | `maton.asana` | projects, tasks, workspaces |
| GitHub | `maton.github` | repos, issues, PRs, releases, labels |
| Google Ads | `maton.google_ads` | accounts, campaigns, ad groups, ads, keywords |
| Google Calendar | `maton.google_calendar` | calendars, events, ACL, freebusy |
| Google Docs | `maton.google_docs` | documents (create / get / write) |
| Google Drive | `maton.google_drive` | files, drives, permissions, comments, revisions |
| Google Mail | `maton.google_mail` | drafts, labels, messages, threads |
| Google Sheets | `maton.google_sheets` | spreadsheets, sheets, values |
| Google Tasks | `maton.google_tasks` | tasklists, tasks |
| HubSpot | `maton.hubspot` | contacts, companies, deals, associations |
| Jira | `maton.jira` | issues, projects, transitions, comments, users |
| Linear | `maton.linear` | issues, projects, cycles, teams (GraphQL) |
| Microsoft Teams | `maton.microsoft_teams` | teams, channels, chats, messages, meetings |
| Notion | `maton.notion` | pages, databases, data sources, blocks, search |
| OneDrive | `maton.one_drive` | drives, items (upload, share, move) |
| Outlook | `maton.outlook` | messages, events, contacts, folders |
| Salesforce | `maton.salesforce` | records, query, search, composites |
| Slack | `maton.slack` | channels, messages, files, reactions, schedules |
| Stripe | `maton.stripe` | customers, charges, invoices, subscriptions |
| Trello | `maton.trello` | boards, cards, lists, checklists, labels |
| YouTube | `maton.youtube` | channels, videos, playlists, comments, search |

## Reliability

Every call goes through an `httpx`-based client with automatic retries. The
defaults are configurable on the constructor:

```python
maton = Maton(
    api_key=...,
    timeout=30.0,      # per-request timeout, seconds
    max_retries=2,     # retry attempts on transient failures
    max_backoff=20.0,  # cap on a single backoff sleep, seconds
)
```

Retries fire on connection errors and on `429 / 500 / 502 / 503 / 504`; other
4xx/5xx surface immediately. Backoff is truncated exponential with full jitter
(botocore standard mode), and honors a server-provided `Retry-After` header.

## Errors

All failures raise a subclass of `MatonError`, each carrying `status_code`,
`request_id`, and the parsed `body`:

| Exception | When |
|---|---|
| `AccessDeniedError` | 401/403 — bad/missing API key or insufficient scope |
| `ResourceNotFoundError` | 404 |
| `TooManyRequestsError` | 429 — also exposes `.retry_after` |
| `ValidationError` | other 4xx (incl. 412 when an action needs a connection) |
| `InternalServerError` | 5xx or unexpected upstream response |
| `APIConnectionError` | network/transport failure (couldn't reach the gateway) |

A handful of apps wrap their vendor-specific error envelopes (e.g. a GraphQL
`errors` array or a Slack `ok: false` payload) in a dedicated subclass, so you
can catch them by app while still falling back to `MatonError`:

| Exception | App |
|---|---|
| `GitHubError` | GitHub GraphQL/API errors |
| `GoogleDriveError` | Google Drive API errors |
| `LinearError` | Linear GraphQL/API errors |
| `SlackError` | Slack API errors |
| `StripeError` | Stripe API errors |

```python
from maton_ai import MatonError, TooManyRequestsError

try:
    maton.google_mail.message.list(q="is:unread", connection=connection_id)
except TooManyRequestsError as exc:
    print("slow down; retry after", exc.retry_after)
except MatonError as exc:
    print(exc.status_code, exc.request_id, exc.body)
```

## Development

This repo uses [Hatch](https://hatch.pypa.io/).

```bash
hatch env create          # set up the default env
hatch run lint            # ruff check + format check
hatch run fmt             # ruff format + autofix
hatch run type            # mypy --strict on src/maton_ai
hatch run test            # pytest
hatch run test:test       # full Python 3.10/3.11/3.12 matrix
hatch run clean           # remove __pycache__ / *.pyc
```

Linting and formatting use [Ruff](https://docs.astral.sh/ruff/) (line length 120) — it
covers pyflakes, isort, bugbear, pyupgrade, and unused-import/variable removal in one tool.

Install the [pre-commit](https://pre-commit.com/) hooks once after setting up your env so
Ruff and basic hygiene checks run on every commit:

```bash
pip install -e ".[dev]"   # or: hatch shell
pre-commit install
```
