Skip to content

API Methods Reference

All methods are async. Import APClient from the top-level package:

from longwei import APClient
import httpx

async with httpx.AsyncClient() as client:
    ap = await APClient.create(
        instance="mastodon.social",
        client=client,
        access_token="your_token",
    )

APClient constructor

APClient(instance, client, access_token, timeout)

Direct instantiation. Prefer APClient.create() for most use cases.

ap = APClient(
    instance="mastodon.social",
    client=client,
    access_token="your_token",   # optional
    timeout=120,                 # optional; defaults to 120 seconds
)
Parameter Type Description
instance str Domain or URL of the instance; trailing slash is stripped
client AsyncClient httpx.AsyncClient to use for requests
access_token str \| None Bearer token; omit for public-only access
timeout int \| None Request timeout in seconds; defaults to 120

APClient.create() (async factory)

Recommended entry point. Calls determine_instance_type() automatically.

ap = await APClient.create(
    instance="mastodon.social",
    client=client,
    access_token="your_token",
    timeout=30,
)

Returns a fully initialised APClient instance.


Instance attributes

After creation the following attributes are available on the instance:

Attribute Type Default Description
instance str Normalised instance URL (https:// prefix added if absent)
instance_type str INSTANCE_TYPE_MASTODON Detected server type
max_status_len int 500 Max characters per status
max_attachments int 4 Max media attachments per status
max_att_size int 10000000 Max attachment size in bytes
supported_mime_types list[str] [] MIME types accepted for uploads
ratelimit_limit int 300 Requests allowed per rate-limit window
ratelimit_remaining int 300 Requests remaining in current window
ratelimit_reset datetime now When the rate-limit window resets
pagination dict {"next": {…}, "prev": {…}} Pagination cursors from last response

Credentials

verify_credentials()

Returns the authenticated account's profile.

account: Account = await ap.verify_credentials()
print(account.username)

Returns: Account

determine_instance_type()

Queries /api/v1/instance and sets instance_type, max_status_len, max_attachments, max_att_size, and supported_mime_types on the instance. Called automatically by APClient.create().

await ap.determine_instance_type()

Returns: None


Timelines

get_public_timeline()

statuses: list[Status] = await ap.get_public_timeline(
    local=False,
    remote=False,
    only_media=False,
    max_id=None,
    since_id=None,
    min_id=None,
    limit=20,
)
Parameter Type Default Description
local bool False Show only local statuses
remote bool False Show only remote statuses
only_media bool False Show only statuses with media attached
max_id str \| None None Return results older than this ID
since_id str \| None None Return results newer than this ID
min_id str \| None None Return results immediately newer than this ID
limit int 20 Max results to return (server max: 40)

Returns: list[Status]

get_home_timeline()

statuses: list[Status] = await ap.get_home_timeline(
    max_id=None,
    since_id=None,
    min_id=None,
    limit=20,
)

Requires authentication. Returns statuses from accounts the authenticated user follows.

Returns: list[Status]

get_hashtag_timeline()

statuses: list[Status] = await ap.get_hashtag_timeline(
    hashtag,
    any_tags=None,
    all_tags=None,
    none_tags=None,
    local=False,
    remote=False,
    only_media=False,
    max_id=None,
    since_id=None,
    min_id=None,
    limit=20,
)
Parameter Type Default Description
hashtag str required Hashtag to query, without the # prefix
any_tags list[str] \| None None Also include statuses with any of these additional tags
all_tags list[str] \| None None Also include statuses that contain all of these tags
none_tags list[str] \| None None Exclude statuses with any of these tags
local bool False Only local statuses
remote bool False Only remote statuses
only_media bool False Only statuses with media
max_id / since_id / min_id str \| None None Pagination cursors
limit int 20 Max results (server max: 40)

Returns: list[Status]

get_account_statuses()

statuses: list[Status] = await ap.get_account_statuses(
    account_id,
    max_id=None,
    min_id=None,
    since_id=None,
    limit=None,
    only_media=None,
    exclude_replies=None,
    exclude_reblogs=None,
    tagged=None,
)
Parameter Type Default Description
account_id str required ID of the account
max_id str \| None None Return statuses older than this ID
min_id str \| None None Return statuses immediately newer than this ID
since_id str \| None None Return statuses newer than this ID
limit int \| None None Maximum number of results (server default: 20, max: 40)
only_media bool \| None None Only return statuses with media attachments
exclude_replies bool \| None None Skip statuses that are replies
exclude_reblogs bool \| None None Skip statuses that are reblogs/boosts
tagged str \| None None Filter by hashtag (without the #)

Returns: list[Status]


Statuses

post_status()

status: Status = await ap.post_status(
    status,
    visibility=Visibility.PUBLIC,
    media_ids=None,
    sensitive=False,
    spoiler_text=None,
    scheduled_at=None,
    in_reply_to_id=None,
    language=None,
    poll_options=None,
    poll_expires_in=None,
    poll_multiple=False,
    poll_hide_totals=False,
)
Parameter Type Default Description
status str required Text content of the status
visibility Visibility Visibility.PUBLIC Who can see the status
media_ids list[str] \| None None IDs from post_media() to attach
sensitive bool False Mark the status as sensitive
spoiler_text str \| None None Content warning text
scheduled_at datetime \| None None Schedule for future posting (at least 5 min ahead); timezone defaults to UTC if naive
in_reply_to_id str \| None None ID of the status being replied to
language str \| None None ISO 639-1 language code (e.g. "en")
poll_options list[str] \| None None Answer strings for an attached poll (at least 2); mutually exclusive with media_ids
poll_expires_in int \| None None Seconds until the poll closes; required when poll_options is set
poll_multiple bool False Allow voters to select multiple options
poll_hide_totals bool False Hide vote counts until the poll ends

Returns: Status

delete_status()

status: Status = await ap.delete_status(
    status,
    delete_only_one=False,
)
Parameter Type Default Description
status str \| Status required Status ID or Status object
delete_only_one bool False Set True to skip the random 0–3 s batch delay

When a Status object is passed on a Pleroma instance, undo_reblog() or undo_favourite() is called first if the status is reblogged or favourited.

Returns: Status (the deleted status)

reblog()

status: Status = await ap.reblog(status_id, visibility=None)
Parameter Type Default Description
status_id str required ID of the status to reblog
visibility Visibility \| None None Override reblog visibility: public, unlisted, or private. Omit to use the account default.

Returns: Status

undo_reblog()

status: Status = await ap.undo_reblog(status)
Parameter Type Description
status str \| Status Status ID or Status object

Returns: Status

undo_favourite()

status: Status = await ap.undo_favourite(status)
Parameter Type Description
status str \| Status Status ID or Status object

Returns: Status


Media

post_media()

Upload a media file. Returns a MediaAttachment (use the id field as an entry in media_ids when calling post_status()).

Attempts POST /api/v2/media first; falls back to POST /api/v1/media on 404. If the server responds with HTTP 202 (still processing), polls until the attachment is ready before returning — the call always resolves with a fully-processed attachment.

result = await ap.post_media(
    file,
    mime_type,
    description=None,
    focus=None,
)
media_id = result.id
Parameter Type Default Description
file IO[bytes] required File-like object opened in binary mode
mime_type str required MIME type, e.g. "image/jpeg"
description str \| None None Alt-text for accessibility
focus tuple[float, float] \| None None Focal point (x, y) in range [-1.0, 1.0]

Returns: MediaAttachment


search()

results = await ap.search(
    query,
    query_type,
    resolve=True,
    following=False,
    account_id=None,
    exclude_unreviewed=False,
    max_id=None,
    min_id=None,
    limit=None,
    offset=None,
)
Parameter Type Default Description
query str required Search query string
query_type SearchType required Constrain results to accounts, hashtags, or statuses
resolve bool True Use WebFinger to resolve unknown remote accounts
following bool False Only include accounts the user follows
account_id str \| None None Restrict status search to this account
exclude_unreviewed bool False Filter unreviewed tags (useful for trending)
max_id str \| None None Results older than this ID
min_id str \| None None Results newer than this ID
limit int \| None None Max results per category (server default: 20, max: 40)
offset int \| None None Skip the first N results

Returns: SearchResults with .accounts, .statuses, and .hashtags lists

Attempts GET /api/v2/search first; falls back to GET /api/v1/search on 404 (e.g. Pleroma). On v1 fallback only query, query_type, resolve, and limit are forwarded — the remaining parameters are silently dropped as they are not part of the v1 spec.


Authentication (static methods)

See the Authentication guide for full details and examples.

Method Description
APClient.create_app(instance_url, client, ...) Register an OAuth app; returns (client_id, client_secret)
APClient.get_auth_token(instance_url, username, password, client, ...) Password grant; returns access token
APClient.generate_authorization_url(instance_url, client_id, ...) Build OAuth redirect URL
APClient.validate_authorization_code(client, instance_url, code, client_id, client_secret) Exchange code for token

Pagination

After every timeline call, pagination cursors are stored on the client:

statuses = await ap.get_public_timeline(limit=20)

next_max_id = ap.pagination["next"]["max_id"]
if next_max_id:
    more = await ap.get_public_timeline(limit=20, max_id=next_max_id)

ap.pagination layout:

{
    "next": {"max_id": str | None, "min_id": str | None},
    "prev": {"max_id": str | None, "min_id": str | None},
}


Rate limits

Rate limit state is updated after every response:

Attribute Description
ap.ratelimit_limit Requests allowed per window
ap.ratelimit_remaining Requests left in current window
ap.ratelimit_reset datetime when window resets

When ratelimit_remaining reaches 0 and the reset time is still in the future, the next call raises RatelimitError before any HTTP request is made. See Error Handling for handling patterns.