Skip to main content

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:

  1. Maton(profile="...")
  2. Maton(api_key="...")
  3. the MATON_API_KEY environment variable
  4. MATON_PROFILE
  5. 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_KEY is a global override that outranks even -p/--profile. In this SDK an explicit profile= argument outranks MATON_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 have MATON_API_KEY set. MATON_PROFILE does not outrank MATON_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

maton_ai-0.2.0.tar.gz (115.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

maton_ai-0.2.0-py3-none-any.whl (138.3 kB view details)

Uploaded Python 3

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

Hashes for maton_ai-0.2.0.tar.gz
Algorithm Hash digest
SHA256 57d24f7879d674d5313b82acfea5c90921b191dc628ae3b9f5d4f39c919e81bf
MD5 df96a8ddc160eba1e361ba1c8bac0f23
BLAKE2b-256 645966ebabd49d0ed7c45fe3747526784f4aaac47e8ea9c2e398dd2ad6a20b63

See more details on using hashes here.

Provenance

The following attestation bundles were made for maton_ai-0.2.0.tar.gz:

Publisher: release-pypi.yml on maton-ai/maton-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for maton_ai-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ae965019632a3d26b8ab7515d7b54c9648eccbcebdffa29becb6b67ddef2cd1a
MD5 c2a3e9f31dc68b04838c6920a0e8f264
BLAKE2b-256 332c557db73c30340eda1e6e57737a8a766e795f97b33d17deca24abda234947

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page