Python wrapper for the Mastodon API
Mastodon.py is an actively maintained Python wrapper for the Mastodon API, providing a feature-complete client for interacting with Mastodon instances. It is currently at version 2.2.1 and receives regular updates to support new Mastodon API features and fix bugs.
Common errors
-
MastodonAPIError: (400, 'Bad Request', 'invalid_grant')
cause This error often indicates issues with user authentication, such as an incorrect access token, mismatched OAuth parameters (scopes, redirect URI), or two-factor authentication being enabled on the user's account.fixVerify the `access_token` is correct and hasn't expired. If using OAuth, ensure the `redirect_uri` and `scopes` passed to `log_in()` match those used in `create_app()` and the authorization URL. If 2FA is enabled on your Mastodon account, consider generating an application-specific password or temporarily disabling 2FA for bot accounts if appropriate, or ensure your OAuth flow is correctly handling the authorization code. -
MastodonAPIError: (404, 'Not Found', 'Record not found')
cause The requested resource (e.g., account, status, media) does not exist on the Mastodon instance or the authenticated user does not have permission to access it.fixDouble-check the ID or URL of the resource you are trying to access. Ensure the `api_base_url` is correct for the instance. Verify that the authenticated user's scope and permissions allow access to the specific API endpoint and resource. -
TypeError: 'NoneType' object is not callable
cause This typically happens when a required argument like `api_base_url` is `None` when a method expects a string, often because `api_base_url` was omitted when creating the `Mastodon` client or `create_app()`.fixAlways explicitly pass the `api_base_url` parameter when initializing `Mastodon` or calling `Mastodon.create_app()`. Example: `mastodon = Mastodon(api_base_url='https://example.social', ...)`. -
MastodonRatelimitError: Rate limit hit, try again in X seconds
cause Your application has exceeded the number of API requests allowed by the Mastodon instance within a given timeframe.fixBy default, `mastodon-py` will wait. If you configured `ratelimit_method='throw'`, you need to implement your own retry logic with a delay. Check the `ratelimit_reset` attribute on the `Mastodon` object to know when to retry, or use `time.sleep()` for the duration indicated in the error message.
Warnings
- breaking Version 2.0.0 introduced a 'massive rework of entities and typing', converting return values to proper classes instead of just AttribAccessDict. While backward compatibility was attempted, it's advised to 'be extra careful about upgrading'.
- breaking In versions prior to 1.7.0, `api_base_url` had a default value (`mastodon.social`), but this was removed. Failing to explicitly pass `api_base_url` to `Mastodon.create_app()` or `Mastodon()` constructor will now raise an error.
- deprecated The library might internally encounter deprecation warnings from the Mastodon API itself due to the older v1 instance API being deprecated. Version 2.1.3 included a fix to handle these warnings, adding a fallback.
- gotcha Two-factor authentication (2FA) on your Mastodon account can prevent `mastodon-py` from logging in successfully via password flow, resulting in an `invalid_grant` error. Additionally, case sensitivity in the login email address can cause the same error.
- gotcha API rate limits can be hit, especially with frequent requests, leading to `MastodonRatelimitError`. While `mastodon-py` provides mechanisms to handle this, improper configuration can still lead to errors.
Install
-
pip install Mastodon.py
Imports
- Mastodon
from mastodon import Mastodon
Quickstart
import os
from mastodon import Mastodon
# --- App Registration (Run once per server/app) ---
# client_id, client_secret = Mastodon.create_app(
# 'MyPythonApp',
# api_base_url = 'https://mastodon.social',
# to_file = 'pytooter_clientcred.secret'
# )
# --- User Login (Run once per user/app) ---
# mastodon = Mastodon(client_id = 'pytooter_clientcred.secret')
# # print(mastodon.auth_request_url())
# # code = input("Enter the OAuth authorization code: ")
# # mastodon.log_in(code=code, to_file="pytooter_usercred.secret")
# --- Usage with existing credentials ---
# It's recommended to store sensitive tokens securely (e.g., environment variables).
# For quick testing, you can load from file if previously saved.
# ACCESS_TOKEN_FILE = 'pytooter_usercred.secret'
# if os.path.exists(ACCESS_TOKEN_FILE):
# api_base_url = None # Will be loaded from file if present
# with open(ACCESS_TOKEN_FILE, 'r') as f:
# # Simple parsing for demo, real-world might use better config handling
# lines = f.readlines()
# for line in lines:
# if 'api_base_url' in line:
# api_base_url = line.split('=')[1].strip()
# break
# mastodon = Mastodon(access_token=ACCESS_TOKEN_FILE, api_base_url=api_base_url)
# else:
MASTODON_ACCESS_TOKEN = os.environ.get('MASTODON_ACCESS_TOKEN', '')
MASTODON_API_BASE_URL = os.environ.get('MASTODON_API_BASE_URL', 'https://mastodon.social')
if not MASTODON_ACCESS_TOKEN:
print("Error: MASTODON_ACCESS_TOKEN environment variable not set. Please set it or uncomment app registration/login code.")
exit(1)
print(f"Connecting to Mastodon instance: {MASTODON_API_BASE_URL}")
mastodon = Mastodon(
access_token=MASTODON_ACCESS_TOKEN,
api_base_url=MASTODON_API_BASE_URL
)
try:
# Get current authenticated user's account details
me = mastodon.account_verify_credentials()
print(f"Successfully authenticated as @{me.acct}")
# Post a status (toot)
status = mastodon.status_post('Hello from mastodon-py! #python #mastodonpy')
print(f"Tooted: {status.url}")
except Exception as e:
print(f"An error occurred: {e}")