Maton Python SDK
Official Python SDK for Maton — connect and automate 150+ apps (Gmail, Slack, GitHub, Notion, HubSpot, Airtable, and more) from Python.
Install
pip install maton-ai
# or
uv add maton-ai
# or
poetry add maton-ai
Quickstart
Sign in once through the browser, then construct the client with no arguments:
import maton_ai
maton_ai.login() # opens a browser; stores the session locally
from maton_ai import Maton
maton = Maton()
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")
Authentication
maton_ai.login() runs an OAuth flow in your browser and stores the session
locally. Nothing else is required: the SDK signs in, renews, and signs out on its
own, with no other Maton tool involved.
maton_ai.login() # sign in, and make it the active session
maton_ai.login(make_active=False) # add a session without switching to it
maton_ai.logout() # revoke and clear the active session
maton_ai.logout("alice@example.com") # sign one account out
When the authorization server refuses, login() raises maton_ai.OAuthError — a
MatonError subclass that carries the server's own error code as .code, so
access_denied (the user declined) is distinguishable from a misconfigured client.
Everything else that can go wrong on the way — discovery, a timeout waiting for the
browser — raises MatonError. logout() clears the local session even when the
revocation call fails, so a machine can always be signed out.
Credentials resolve in this order:
Maton(profile="...")Maton(api_key="...")- the
MATON_API_KEYenvironment variable MATON_PROFILE- the active stored session, or the sole one when none is marked active
Explicit credentials always win over ambient machine state. Passing both
profile= and api_key= is rejected as ambiguous, and a named profile that
cannot be resolved raises rather than quietly authenticating as another account.
One deliberate difference from the Maton CLI. In the CLI,
MATON_API_KEYis a global override that outranks even-p/--profile. In this SDK an explicitprofile=argument outranksMATON_API_KEY, because an argument written in code is a stronger signal of intent than an exported variable, and because a multi-tenant process must be able to select an account on a machine that happens to haveMATON_API_KEYset.MATON_PROFILEdoes not outrankMATON_API_KEY— between two ambient sources, the CLI's order is kept.
maton = Maton(profile="alice@example.com") # a specific account
An API key remains the right choice where a browser sign-in is impossible, such as CI:
maton = Maton(api_key=os.environ["MATON_API_KEY"])
Where the session is stored
Session metadata goes to the python section of credentials.json in
~/.config/maton on macOS and Linux, or %AppData%\Maton on Windows. The file
is shared with the other Maton SDKs, while each SDK keeps independent profiles
and an independent active-profile selection. $MATON_CONFIG_DIR overrides the
directory outright, and $XDG_CONFIG_HOME/maton takes precedence over the
defaults. The tokens themselves go to the OS keyring when the optional extra is
installed:
pip install "maton-ai[keyring]"
Without it, tokens are written to credentials.json in plaintext at mode 0600, and
login() warns that it did so. Installing the extra is recommended on any
machine where that file is backed up or synced.
Access tokens are short-lived; the SDK renews them in-process from the stored refresh token, so a long-running client keeps working without re-authenticating.
The same pattern works for every supported app:
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):
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:
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:
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
| 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:
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 |
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)
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file maton_ai-0.2.0.tar.gz.
File metadata
- Download URL: maton_ai-0.2.0.tar.gz
- Upload date:
- Size: 115.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57d24f7879d674d5313b82acfea5c90921b191dc628ae3b9f5d4f39c919e81bf
|
|
| MD5 |
df96a8ddc160eba1e361ba1c8bac0f23
|
|
| BLAKE2b-256 |
645966ebabd49d0ed7c45fe3747526784f4aaac47e8ea9c2e398dd2ad6a20b63
|
Provenance
The following attestation bundles were made for maton_ai-0.2.0.tar.gz:
Publisher:
release-pypi.yml on maton-ai/maton-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maton_ai-0.2.0.tar.gz -
Subject digest:
57d24f7879d674d5313b82acfea5c90921b191dc628ae3b9f5d4f39c919e81bf - Sigstore transparency entry: 2589802079
- Sigstore integration time:
-
Permalink:
maton-ai/maton-py@f72374aa77fb3c063076476ca23433e7d5a44511 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/maton-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@f72374aa77fb3c063076476ca23433e7d5a44511 -
Trigger Event:
push
-
Statement type:
File details
Details for the file maton_ai-0.2.0-py3-none-any.whl.
File metadata
- Download URL: maton_ai-0.2.0-py3-none-any.whl
- Upload date:
- Size: 138.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae965019632a3d26b8ab7515d7b54c9648eccbcebdffa29becb6b67ddef2cd1a
|
|
| MD5 |
c2a3e9f31dc68b04838c6920a0e8f264
|
|
| BLAKE2b-256 |
332c557db73c30340eda1e6e57737a8a766e795f97b33d17deca24abda234947
|
Provenance
The following attestation bundles were made for maton_ai-0.2.0-py3-none-any.whl:
Publisher:
release-pypi.yml on maton-ai/maton-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maton_ai-0.2.0-py3-none-any.whl -
Subject digest:
ae965019632a3d26b8ab7515d7b54c9648eccbcebdffa29becb6b67ddef2cd1a - Sigstore transparency entry: 2589802211
- Sigstore integration time:
-
Permalink:
maton-ai/maton-py@f72374aa77fb3c063076476ca23433e7d5a44511 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/maton-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@f72374aa77fb3c063076476ca23433e7d5a44511 -
Trigger Event:
push
-
Statement type: